@logicflow/extension 2.1.4 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +13 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/es/bpmn-adapter/index.d.ts +84 -1
- package/es/bpmn-adapter/index.js +235 -12
- package/es/bpmn-adapter/json2xml.d.ts +10 -1
- package/es/bpmn-adapter/json2xml.js +28 -4
- package/es/bpmn-adapter/xml2json.js +2 -7
- package/es/components/mini-map/index.js +10 -3
- package/es/tools/proximity-connect/index.d.ts +8 -0
- package/es/tools/proximity-connect/index.js +9 -4
- package/es/tools/snapshot/index.d.ts +8 -0
- package/es/tools/snapshot/index.js +2 -2
- package/lib/bpmn-adapter/index.d.ts +84 -1
- package/lib/bpmn-adapter/index.js +235 -12
- package/lib/bpmn-adapter/json2xml.d.ts +10 -1
- package/lib/bpmn-adapter/json2xml.js +29 -4
- package/lib/bpmn-adapter/xml2json.js +2 -7
- package/lib/components/mini-map/index.js +10 -3
- package/lib/tools/proximity-connect/index.d.ts +8 -0
- package/lib/tools/proximity-connect/index.js +9 -4
- package/lib/tools/snapshot/index.d.ts +8 -0
- package/lib/tools/snapshot/index.js +2 -2
- package/package.json +5 -5
- package/src/bpmn-adapter/index.ts +256 -17
- package/src/bpmn-adapter/json2xml.ts +30 -4
- package/src/bpmn-adapter/xml2json.ts +2 -7
- package/src/components/mini-map/index.ts +12 -3
- package/src/tools/proximity-connect/index.ts +14 -4
- package/src/tools/snapshot/index.ts +10 -2
- package/stats.html +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogicFlow 节点配置(导入/导出过程中使用的中间结构)
|
|
3
|
+
* - id/type/x/y:节点基本信息
|
|
4
|
+
* - text:节点文本的中心坐标与内容(值为未转义的原始字符串)
|
|
5
|
+
* - properties:节点的额外属性(会保留到 BPMN 的扩展字段)
|
|
6
|
+
*/
|
|
1
7
|
type NodeConfig = {
|
|
2
8
|
id: string;
|
|
3
9
|
properties?: Record<string, unknown>;
|
|
@@ -10,10 +16,20 @@ type NodeConfig = {
|
|
|
10
16
|
x: number;
|
|
11
17
|
y: number;
|
|
12
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* 点坐标结构(用于边的路径点)
|
|
21
|
+
*/
|
|
13
22
|
type Point = {
|
|
14
23
|
x: number;
|
|
15
24
|
y: number;
|
|
16
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* LogicFlow 边配置(导入/导出过程中使用的中间结构)
|
|
28
|
+
* - id/type/sourceNodeId/targetNodeId:边的基本信息
|
|
29
|
+
* - pointsList:边的路径点(用于 BPMN 的 di:waypoint)
|
|
30
|
+
* - text:边文本的位置与内容(值为未转义的原始字符串)
|
|
31
|
+
* - properties:边的扩展属性
|
|
32
|
+
*/
|
|
17
33
|
type EdgeConfig = {
|
|
18
34
|
id: string;
|
|
19
35
|
sourceNodeId: string;
|
|
@@ -35,11 +51,29 @@ type EdgeConfig = {
|
|
|
35
51
|
pointsList?: Point[];
|
|
36
52
|
properties: Record<string, unknown>;
|
|
37
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* 将普通 JSON 转换为 XML 风格 JSON(xmlJson)
|
|
56
|
+
* 输入:任意 JSON 对象;可选的保留属性字段 retainedFields
|
|
57
|
+
* 输出:遵循 XML 属性前缀约定的 xmlJson(属性键以 '-' 开头)
|
|
58
|
+
* 规则:
|
|
59
|
+
* - 原始字符串直接返回;数组逐项转换;对象根据键类型决定是否加 '-' 前缀。
|
|
60
|
+
* - 保留字段(fields)中出现的键以属性形式(带 '-')保留,否则视为子节点。
|
|
61
|
+
*/
|
|
38
62
|
declare function toXmlJson(retainedFields?: string[]): (json: string | any[] | Record<string, any>) => any;
|
|
39
63
|
/**
|
|
40
|
-
* 将xmlJson
|
|
64
|
+
* 将 XML 风格 JSON(xmlJson)转换回普通 JSON(内部使用)
|
|
65
|
+
* 输入:遵循 '-' 属性前缀约定的 xmlJson
|
|
66
|
+
* 输出:去除前缀并恢复原有结构的普通 JSON
|
|
41
67
|
*/
|
|
42
68
|
declare function toNormalJson(xmlJson: any): {};
|
|
69
|
+
/**
|
|
70
|
+
* BpmnAdapter:基础适配器
|
|
71
|
+
*
|
|
72
|
+
* 作用:在 LogicFlow 数据与 BPMN JSON 之间进行转换,并注入 adapterIn/adapterOut 钩子。
|
|
73
|
+
* - processAttributes:导出时 BPMN process 的基础属性(可配置 isExecutable、id 等)。
|
|
74
|
+
* - definitionAttributes:导出时 BPMN definitions 的基础属性与命名空间声明。
|
|
75
|
+
* - shapeConfigMap:不同 BPMN 元素类型的默认宽高,用于坐标/Bounds 计算。
|
|
76
|
+
*/
|
|
43
77
|
declare class BpmnAdapter {
|
|
44
78
|
static pluginName: string;
|
|
45
79
|
static shapeConfigMap: Map<any, any>;
|
|
@@ -59,6 +93,11 @@ declare class BpmnAdapter {
|
|
|
59
93
|
['-exporterVersion']: string;
|
|
60
94
|
[key: string]: any;
|
|
61
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* 构造函数
|
|
98
|
+
* - 注入 LogicFlow 的 adapterIn/adapterOut(处理 JSON 方向的适配)
|
|
99
|
+
* - 初始化 process 与 definitions 的基础属性
|
|
100
|
+
*/
|
|
62
101
|
constructor({ lf }: {
|
|
63
102
|
lf: any;
|
|
64
103
|
});
|
|
@@ -68,6 +107,13 @@ declare class BpmnAdapter {
|
|
|
68
107
|
* ["properties", "startPoint", "endPoint", "pointsList"]合并,
|
|
69
108
|
* 这意味着出现在这个数组里的字段当它的值是数组或是对象时不会被视为一个节点而是一个属性。
|
|
70
109
|
*/
|
|
110
|
+
/**
|
|
111
|
+
* adapterOut:将 LogicFlow 图数据转换为 BPMN JSON
|
|
112
|
+
* 输入:
|
|
113
|
+
* - data:LogicFlow GraphData
|
|
114
|
+
* - retainedFields:扩展属性保留字段
|
|
115
|
+
* 输出:BPMN JSON(包含 definitions/process/diagram/plane)
|
|
116
|
+
*/
|
|
71
117
|
adapterOut: (data: any, retainedFields?: string[]) => {
|
|
72
118
|
'bpmn:definitions': {
|
|
73
119
|
[key: string]: any;
|
|
@@ -82,18 +128,55 @@ declare class BpmnAdapter {
|
|
|
82
128
|
"-exporterVersion": string;
|
|
83
129
|
};
|
|
84
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* adapterIn:将 BPMN JSON 转换为 LogicFlow 图数据
|
|
133
|
+
* 输入:bpmnData:BPMN JSON
|
|
134
|
+
* 输出:GraphConfigData(nodes/edges)
|
|
135
|
+
*/
|
|
85
136
|
adapterIn: (bpmnData: any) => {
|
|
86
137
|
nodes: NodeConfig[];
|
|
87
138
|
edges: EdgeConfig[];
|
|
88
139
|
} | undefined;
|
|
89
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* BpmnXmlAdapter:XML 适配器(继承 BpmnAdapter)
|
|
143
|
+
*
|
|
144
|
+
* 作用:处理 XML 输入/输出的适配,使用 xml2json/json2xml 完成格式转换。
|
|
145
|
+
* 特殊处理:在 XML 导入前对 name 属性的非法字符进行预处理转义,提升容错。
|
|
146
|
+
*/
|
|
90
147
|
declare class BpmnXmlAdapter extends BpmnAdapter {
|
|
91
148
|
static pluginName: string;
|
|
149
|
+
/**
|
|
150
|
+
* 构造函数
|
|
151
|
+
* - 覆盖 LogicFlow 的 adapterIn/adapterOut,使其面向 XML 输入与输出。
|
|
152
|
+
*/
|
|
92
153
|
constructor(data: any);
|
|
154
|
+
/**
|
|
155
|
+
* 预处理 XML:仅对 name 属性值进行非法字符转义(<, >, &),避免 DOM 解析失败。
|
|
156
|
+
* 注意:不影响已合法的实体(如 &),仅在属性值中生效,不修改其它内容。
|
|
157
|
+
*/
|
|
158
|
+
private sanitizeNameAttributes;
|
|
159
|
+
/**
|
|
160
|
+
* adapterXmlIn:将 BPMN XML 转换为 LogicFlow 图数据
|
|
161
|
+
* 输入:bpmnData:XML 字符串或对象
|
|
162
|
+
* 步骤:
|
|
163
|
+
* 1) 若为字符串,先对 name 属性进行预处理转义;
|
|
164
|
+
* 2) 使用 lfXml2Json 转换为 BPMN JSON;
|
|
165
|
+
* 3) 调用基础 adapterIn 转换为 GraphData。
|
|
166
|
+
*/
|
|
93
167
|
adapterXmlIn: (bpmnData: any) => {
|
|
94
168
|
nodes: NodeConfig[];
|
|
95
169
|
edges: EdgeConfig[];
|
|
96
170
|
} | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* adapterXmlOut:将 LogicFlow 图数据转换为 BPMN XML
|
|
173
|
+
* 输入:
|
|
174
|
+
* - data:GraphData
|
|
175
|
+
* - retainedFields:保留属性字段
|
|
176
|
+
* 步骤:
|
|
177
|
+
* 1) 调用基础 adapterOut 生成 BPMN JSON;
|
|
178
|
+
* 2) 使用 lfJson2Xml 转为合法的 XML 字符串(包含属性与文本的转义)。
|
|
179
|
+
*/
|
|
97
180
|
adapterXmlOut: (data: any, retainedFields?: string[]) => string;
|
|
98
181
|
}
|
|
99
182
|
export { BpmnAdapter, BpmnXmlAdapter, toXmlJson, toNormalJson };
|
package/es/bpmn-adapter/index.js
CHANGED
|
@@ -43,7 +43,23 @@ var __read = (this && this.__read) || function (o, n) {
|
|
|
43
43
|
import { getBpmnId } from './bpmnIds';
|
|
44
44
|
import { handleAttributes, lfJson2Xml } from './json2xml';
|
|
45
45
|
import { lfXml2Json } from './xml2json';
|
|
46
|
+
/**
|
|
47
|
+
* 模块说明(BPMN Adapter)
|
|
48
|
+
*
|
|
49
|
+
* 该模块负责在 LogicFlow 内部图数据(GraphData)与 BPMN XML/JSON 之间进行双向转换:
|
|
50
|
+
* - adapterOut:将 LogicFlow 图数据转换为 BPMN JSON(随后由 json2xml 转为 XML)
|
|
51
|
+
* - adapterIn:将 BPMN JSON 转换为 LogicFlow 图数据(如果是 XML,则先经 xml2json 转为 JSON)
|
|
52
|
+
*
|
|
53
|
+
* 设计要点与特殊处理:
|
|
54
|
+
* - BPMN XML 的属性在 JSON 中以前缀 '-' 表示(如 '-id'、'-name'),本模块严格遵循该约定。
|
|
55
|
+
* - XML 中同名子节点可能出现多次,xml2json 解析后会以数组表示;本模块对数组与单对象场景均做兼容处理。
|
|
56
|
+
* - BPMN 画布坐标以元素左上角为基准,而 LogicFlow 以元素中心为基准;转换时需进行坐标基准转换。
|
|
57
|
+
* - 文本内容在导出时进行 XML 转义,在导入时进行反转义,确保特殊字符(如 <, >, & 等)能被正确保留。
|
|
58
|
+
*/
|
|
46
59
|
import { ExclusiveGatewayConfig, StartEventConfig, EndEventConfig, ServiceTaskConfig, UserTaskConfig, } from '../bpmn/constant';
|
|
60
|
+
/**
|
|
61
|
+
* BPMN 元素类型映射(用于在 JSON 中定位具体的 BPMN 节点类型)
|
|
62
|
+
*/
|
|
47
63
|
var BpmnElements;
|
|
48
64
|
(function (BpmnElements) {
|
|
49
65
|
BpmnElements["START"] = "bpmn:startEvent";
|
|
@@ -53,6 +69,11 @@ var BpmnElements;
|
|
|
53
69
|
BpmnElements["SYSTEM"] = "bpmn:serviceTask";
|
|
54
70
|
BpmnElements["FLOW"] = "bpmn:sequenceFlow";
|
|
55
71
|
})(BpmnElements || (BpmnElements = {}));
|
|
72
|
+
/**
|
|
73
|
+
* BPMN 过程元素的标准属性键列表
|
|
74
|
+
* - 在解析 `processValue` 时,这些键会被视为标准属性而非扩展属性;
|
|
75
|
+
* - 其余未在列表中的键会进入 LogicFlow 的 `properties` 中,以保留扩展数据。
|
|
76
|
+
*/
|
|
56
77
|
var defaultAttrs = [
|
|
57
78
|
'-name',
|
|
58
79
|
'-id',
|
|
@@ -71,17 +92,49 @@ var defaultAttrs = [
|
|
|
71
92
|
* 这意味着出现在这个数组里的字段当它的值是数组或是对象时不会被视为一个节点而是一个属性
|
|
72
93
|
* @reference node type reference https://www.w3schools.com/xml/dom_nodetype.asp
|
|
73
94
|
*/
|
|
95
|
+
/**
|
|
96
|
+
* 导出至 BPMN JSON 时,作为属性保留的字段列表
|
|
97
|
+
* - 当这些字段的值为对象或数组时,仍视为属性(在 JSON 中以 '-' 前缀表示),而非子节点。
|
|
98
|
+
*/
|
|
74
99
|
var defaultRetainedFields = [
|
|
75
100
|
'properties',
|
|
76
101
|
'startPoint',
|
|
77
102
|
'endPoint',
|
|
78
103
|
'pointsList',
|
|
79
104
|
];
|
|
105
|
+
/**
|
|
106
|
+
* XML 实体反转义:
|
|
107
|
+
* - 将常见的 XML 实体还原为字符:`<`→`<`、`>`→`>`、`&`→`&`、`"`→`"`、`'`→`'`;保障流程图能正常回填
|
|
108
|
+
* - 使用 `String(text || '')` 规范化输入,避免 `null/undefined` 导致错误;
|
|
109
|
+
* - 注意:此实现为单次替换,若存在嵌套/二次编码(例如 `&lt;`),会先还原为 `<`,
|
|
110
|
+
* 如需完全解码,可在外层循环调用或调整替换顺序策略。
|
|
111
|
+
*/
|
|
112
|
+
var unescapeXml = function (text) {
|
|
113
|
+
return String(text || '')
|
|
114
|
+
.replace(/</g, '<')
|
|
115
|
+
.replace(/>/g, '>')
|
|
116
|
+
.replace(/&/g, '&')
|
|
117
|
+
.replace(/"/g, '"')
|
|
118
|
+
.replace(/'/g, "'");
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* 将普通 JSON 转换为 XML 风格 JSON(xmlJson)
|
|
122
|
+
* 输入:任意 JSON 对象;可选的保留属性字段 retainedFields
|
|
123
|
+
* 输出:遵循 XML 属性前缀约定的 xmlJson(属性键以 '-' 开头)
|
|
124
|
+
* 规则:
|
|
125
|
+
* - 原始字符串直接返回;数组逐项转换;对象根据键类型决定是否加 '-' 前缀。
|
|
126
|
+
* - 保留字段(fields)中出现的键以属性形式(带 '-')保留,否则视为子节点。
|
|
127
|
+
*/
|
|
80
128
|
function toXmlJson(retainedFields) {
|
|
81
129
|
var fields = retainedFields
|
|
82
130
|
? defaultRetainedFields.concat(retainedFields)
|
|
83
131
|
: defaultRetainedFields;
|
|
84
132
|
return function (json) {
|
|
133
|
+
/**
|
|
134
|
+
* 递归转换核心方法
|
|
135
|
+
* @param obj 输入对象/数组/字符串
|
|
136
|
+
* @returns 转换后的 xmlJson
|
|
137
|
+
*/
|
|
85
138
|
function ToXmlJson(obj) {
|
|
86
139
|
var xmlJson = {};
|
|
87
140
|
if (typeof obj === 'string') {
|
|
@@ -115,7 +168,9 @@ function toXmlJson(retainedFields) {
|
|
|
115
168
|
};
|
|
116
169
|
}
|
|
117
170
|
/**
|
|
118
|
-
* 将xmlJson
|
|
171
|
+
* 将 XML 风格 JSON(xmlJson)转换回普通 JSON(内部使用)
|
|
172
|
+
* 输入:遵循 '-' 属性前缀约定的 xmlJson
|
|
173
|
+
* 输出:去除前缀并恢复原有结构的普通 JSON
|
|
119
174
|
*/
|
|
120
175
|
function toNormalJson(xmlJson) {
|
|
121
176
|
var json = {};
|
|
@@ -148,6 +203,18 @@ function toNormalJson(xmlJson) {
|
|
|
148
203
|
* 2)如果只有一个子元素,json中表示为正常属性
|
|
149
204
|
* 3)如果是多个子元素,json中使用数组存储
|
|
150
205
|
*/
|
|
206
|
+
/**
|
|
207
|
+
* 将 LogicFlow 图数据中的节点与边转换为 BPMN 的 process 数据结构
|
|
208
|
+
* 输入:
|
|
209
|
+
* - bpmnProcessData:输出目标对象(会被填充 '-id'、各 bpmn:* 节点以及 sequenceFlow)
|
|
210
|
+
* - data:LogicFlow 图数据(nodes/edges)
|
|
211
|
+
* - retainedFields:可选保留属性字段,用于控制属性与子节点的映射
|
|
212
|
+
* 输出:直接修改 bpmnProcessData
|
|
213
|
+
* 特殊处理:
|
|
214
|
+
* - 节点文本(node.text.value)作为 BPMN 的 '-name' 属性;
|
|
215
|
+
* - 维护 incoming/outgoing 的顺序,保证解析兼容性;
|
|
216
|
+
* - 多子元素时转为数组结构(XML 约定)。
|
|
217
|
+
*/
|
|
151
218
|
function convertLf2ProcessData(bpmnProcessData, data, retainedFields) {
|
|
152
219
|
var nodeMap = new Map();
|
|
153
220
|
data.nodes.forEach(function (node) {
|
|
@@ -221,6 +288,16 @@ function convertLf2ProcessData(bpmnProcessData, data, retainedFields) {
|
|
|
221
288
|
/**
|
|
222
289
|
* adapterOut 设置bpmn diagram信息
|
|
223
290
|
*/
|
|
291
|
+
/**
|
|
292
|
+
* 将 LogicFlow 图数据转换为 BPMN 的图形数据(BPMNDiagram/BPMNPlane 下的 Shape 与 Edge)
|
|
293
|
+
* 输入:
|
|
294
|
+
* - bpmnDiagramData:输出目标对象(填充 BPMNShape/BPMNEdge)
|
|
295
|
+
* - data:LogicFlow 图数据(nodes/edges)
|
|
296
|
+
* 输出:直接修改 bpmnDiagramData
|
|
297
|
+
* 特殊处理:
|
|
298
|
+
* - 节点坐标从中心点转换为左上角基准;
|
|
299
|
+
* - 文本的显示边界(Bounds)根据文本长度近似计算,用于在 BPMN 渲染器正确定位标签。
|
|
300
|
+
*/
|
|
224
301
|
function convertLf2DiagramData(bpmnDiagramData, data) {
|
|
225
302
|
bpmnDiagramData['bpmndi:BPMNEdge'] = data.edges.map(function (edge) {
|
|
226
303
|
var _a;
|
|
@@ -289,21 +366,37 @@ function convertLf2DiagramData(bpmnDiagramData, data) {
|
|
|
289
366
|
/**
|
|
290
367
|
* 将bpmn数据转换为LogicFlow内部能识别数据
|
|
291
368
|
*/
|
|
369
|
+
/**
|
|
370
|
+
* 将 BPMN JSON 转换为 LogicFlow 可识别的图数据
|
|
371
|
+
* 输入:
|
|
372
|
+
* - bpmnData:包含 'bpmn:definitions' 的 BPMN JSON
|
|
373
|
+
* 输出:{ nodes, edges }:LogicFlow 的 GraphConfigData
|
|
374
|
+
* 特殊处理:
|
|
375
|
+
* - 若缺失 process 或 plane,返回空数据以避免渲染错误。
|
|
376
|
+
*/
|
|
292
377
|
function convertBpmn2LfData(bpmnData) {
|
|
293
378
|
var nodes = [];
|
|
294
379
|
var edges = [];
|
|
295
380
|
var definitions = bpmnData['bpmn:definitions'];
|
|
296
381
|
if (definitions) {
|
|
382
|
+
// 如后续需多图/多流程支持,再扩展为遍历与合并,现在看起来是没有这个场景
|
|
297
383
|
var process_1 = definitions['bpmn:process'];
|
|
384
|
+
var diagram = definitions['bpmndi:BPMNDiagram'];
|
|
385
|
+
var plane_1 = diagram === null || diagram === void 0 ? void 0 : diagram['bpmndi:BPMNPlane'];
|
|
386
|
+
if (!process_1 || !plane_1) {
|
|
387
|
+
return { nodes: nodes, edges: edges };
|
|
388
|
+
}
|
|
298
389
|
Object.keys(process_1).forEach(function (key) {
|
|
299
390
|
if (key.indexOf('bpmn:') === 0) {
|
|
300
391
|
var value = process_1[key];
|
|
301
392
|
if (key === BpmnElements.FLOW) {
|
|
302
|
-
var
|
|
393
|
+
var edgesRaw = plane_1['bpmndi:BPMNEdge'];
|
|
394
|
+
var bpmnEdges = Array.isArray(edgesRaw) ? edgesRaw : edgesRaw;
|
|
303
395
|
edges = getLfEdges(value, bpmnEdges);
|
|
304
396
|
}
|
|
305
397
|
else {
|
|
306
|
-
var
|
|
398
|
+
var shapesRaw = plane_1['bpmndi:BPMNShape'];
|
|
399
|
+
var shapes = Array.isArray(shapesRaw) ? shapesRaw : shapesRaw;
|
|
307
400
|
nodes = nodes.concat(getLfNodes(value, shapes, key));
|
|
308
401
|
}
|
|
309
402
|
}
|
|
@@ -314,6 +407,14 @@ function convertBpmn2LfData(bpmnData) {
|
|
|
314
407
|
edges: edges,
|
|
315
408
|
};
|
|
316
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* 根据 BPMN 的 process 子节点与 plane 中的 BPMNShape 生成 LogicFlow 节点数组
|
|
412
|
+
* 输入:
|
|
413
|
+
* - value:当前类型(如 bpmn:userTask)的值,可能为对象或数组
|
|
414
|
+
* - shapes:plane['bpmndi:BPMNShape'],可能为对象或数组
|
|
415
|
+
* - key:当前处理的 BPMN 类型键名(如 'bpmn:userTask')
|
|
416
|
+
* 输出:LogicFlow 节点数组
|
|
417
|
+
*/
|
|
317
418
|
function getLfNodes(value, shapes, key) {
|
|
318
419
|
var nodes = [];
|
|
319
420
|
if (Array.isArray(value)) {
|
|
@@ -343,10 +444,23 @@ function getLfNodes(value, shapes, key) {
|
|
|
343
444
|
}
|
|
344
445
|
return nodes;
|
|
345
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* 将单个 BPMNShape 与其对应的 process 节点合成为 LogicFlow 节点配置
|
|
449
|
+
* 输入:
|
|
450
|
+
* - shapeValue:plane 中的 BPMNShape(包含 Bounds 与可选 BPMNLabel)
|
|
451
|
+
* - type:BPMN 节点类型键(如 'bpmn:userTask')
|
|
452
|
+
* - processValue:process 中对应的节点对象(包含 '-id'、'-name' 等)
|
|
453
|
+
* 输出:LogicFlow NodeConfig
|
|
454
|
+
* 特殊处理:
|
|
455
|
+
* - 坐标从左上角转为中心点;
|
|
456
|
+
* - 文本从 '-name' 读取并进行 XML 实体反转义;
|
|
457
|
+
* - 文本位置优先使用 BPMNLabel 的 Bounds。
|
|
458
|
+
*/
|
|
346
459
|
function getNodeConfig(shapeValue, type, processValue) {
|
|
347
460
|
var x = Number(shapeValue['dc:Bounds']['-x']);
|
|
348
461
|
var y = Number(shapeValue['dc:Bounds']['-y']);
|
|
349
|
-
|
|
462
|
+
// 反转义 XML 实体,确保导入后文本包含特殊字符时能被完整还原
|
|
463
|
+
var name = unescapeXml(processValue['-name']);
|
|
350
464
|
var shapeConfig = BpmnAdapter.shapeConfigMap.get(type);
|
|
351
465
|
if (shapeConfig) {
|
|
352
466
|
x += shapeConfig.width / 2;
|
|
@@ -392,6 +506,13 @@ function getNodeConfig(shapeValue, type, processValue) {
|
|
|
392
506
|
}
|
|
393
507
|
return nodeConfig;
|
|
394
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* 根据 BPMN 的 sequenceFlow 与 BPMNEdge 生成 LogicFlow 边数组
|
|
511
|
+
* 输入:
|
|
512
|
+
* - value:process['bpmn:sequenceFlow'],对象或数组
|
|
513
|
+
* - bpmnEdges:plane['bpmndi:BPMNEdge'],对象或数组
|
|
514
|
+
* 输出:LogicFlow 边数组
|
|
515
|
+
*/
|
|
395
516
|
function getLfEdges(value, bpmnEdges) {
|
|
396
517
|
var edges = [];
|
|
397
518
|
if (Array.isArray(value)) {
|
|
@@ -418,11 +539,29 @@ function getLfEdges(value, bpmnEdges) {
|
|
|
418
539
|
}
|
|
419
540
|
return edges;
|
|
420
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* 将单个 BPMNEdge 与其对应的 sequenceFlow 合成为 LogicFlow 边配置
|
|
544
|
+
* 输入:
|
|
545
|
+
* - edgeValue:BPMNEdge(包含 di:waypoint 以及可选 BPMNLabel/Bounds)
|
|
546
|
+
* - processValue:sequenceFlow(包含 '-id'、'-sourceRef'、'-targetRef'、'-name' 等)
|
|
547
|
+
* 输出:LogicFlow EdgeConfig
|
|
548
|
+
* 特殊处理:
|
|
549
|
+
* - 文本从 '-name' 读取并进行 XML 实体反转义;
|
|
550
|
+
* - 若缺失 BPMNLabel,则以边的几何中心近似作为文本位置;
|
|
551
|
+
* - pointsList 由 waypoints 转换得到,数值类型统一为 Number。
|
|
552
|
+
*/
|
|
421
553
|
function getEdgeConfig(edgeValue, processValue) {
|
|
422
554
|
var text;
|
|
423
|
-
|
|
555
|
+
// 反转义 XML 实体,确保导入后文本包含特殊字符时能被完整还原
|
|
556
|
+
var textVal = processValue['-name']
|
|
557
|
+
? unescapeXml("".concat(processValue['-name']))
|
|
558
|
+
: '';
|
|
424
559
|
if (textVal) {
|
|
425
|
-
var textBounds =
|
|
560
|
+
var textBounds = void 0;
|
|
561
|
+
if (edgeValue['bpmndi:BPMNLabel'] &&
|
|
562
|
+
edgeValue['bpmndi:BPMNLabel']['dc:Bounds']) {
|
|
563
|
+
textBounds = edgeValue['bpmndi:BPMNLabel']['dc:Bounds'];
|
|
564
|
+
}
|
|
426
565
|
// 如果边文本换行,则其偏移量应该是最长一行的位置
|
|
427
566
|
var textLength_1 = 0;
|
|
428
567
|
textVal.split('\n').forEach(function (textSpan) {
|
|
@@ -430,11 +569,26 @@ function getEdgeConfig(edgeValue, processValue) {
|
|
|
430
569
|
textLength_1 = textSpan.length;
|
|
431
570
|
}
|
|
432
571
|
});
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
572
|
+
if (textBounds) {
|
|
573
|
+
text = {
|
|
574
|
+
value: textVal,
|
|
575
|
+
x: Number(textBounds['-x']) + (textLength_1 * 10) / 2,
|
|
576
|
+
y: Number(textBounds['-y']) + 7,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
// 兼容缺少 BPMNLabel 的图:使用边的几何中心作为文本位置
|
|
581
|
+
var waypoints = edgeValue['di:waypoint'] || [];
|
|
582
|
+
var first = waypoints[0];
|
|
583
|
+
var last = waypoints[waypoints.length - 1] || first;
|
|
584
|
+
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;
|
|
585
|
+
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;
|
|
586
|
+
text = {
|
|
587
|
+
value: textVal,
|
|
588
|
+
x: centerX,
|
|
589
|
+
y: centerY,
|
|
590
|
+
};
|
|
591
|
+
}
|
|
438
592
|
}
|
|
439
593
|
var properties;
|
|
440
594
|
// 判断是否存在额外的属性,将额外的属性放到properties中
|
|
@@ -465,7 +619,20 @@ function getEdgeConfig(edgeValue, processValue) {
|
|
|
465
619
|
}
|
|
466
620
|
return edge;
|
|
467
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* BpmnAdapter:基础适配器
|
|
624
|
+
*
|
|
625
|
+
* 作用:在 LogicFlow 数据与 BPMN JSON 之间进行转换,并注入 adapterIn/adapterOut 钩子。
|
|
626
|
+
* - processAttributes:导出时 BPMN process 的基础属性(可配置 isExecutable、id 等)。
|
|
627
|
+
* - definitionAttributes:导出时 BPMN definitions 的基础属性与命名空间声明。
|
|
628
|
+
* - shapeConfigMap:不同 BPMN 元素类型的默认宽高,用于坐标/Bounds 计算。
|
|
629
|
+
*/
|
|
468
630
|
var BpmnAdapter = /** @class */ (function () {
|
|
631
|
+
/**
|
|
632
|
+
* 构造函数
|
|
633
|
+
* - 注入 LogicFlow 的 adapterIn/adapterOut(处理 JSON 方向的适配)
|
|
634
|
+
* - 初始化 process 与 definitions 的基础属性
|
|
635
|
+
*/
|
|
469
636
|
function BpmnAdapter(_a) {
|
|
470
637
|
var lf = _a.lf;
|
|
471
638
|
var _this = this;
|
|
@@ -474,6 +641,13 @@ var BpmnAdapter = /** @class */ (function () {
|
|
|
474
641
|
* ["properties", "startPoint", "endPoint", "pointsList"]合并,
|
|
475
642
|
* 这意味着出现在这个数组里的字段当它的值是数组或是对象时不会被视为一个节点而是一个属性。
|
|
476
643
|
*/
|
|
644
|
+
/**
|
|
645
|
+
* adapterOut:将 LogicFlow 图数据转换为 BPMN JSON
|
|
646
|
+
* 输入:
|
|
647
|
+
* - data:LogicFlow GraphData
|
|
648
|
+
* - retainedFields:扩展属性保留字段
|
|
649
|
+
* 输出:BPMN JSON(包含 definitions/process/diagram/plane)
|
|
650
|
+
*/
|
|
477
651
|
this.adapterOut = function (data, retainedFields) {
|
|
478
652
|
var bpmnProcessData = __assign({}, _this.processAttributes);
|
|
479
653
|
convertLf2ProcessData(bpmnProcessData, data, retainedFields);
|
|
@@ -493,6 +667,11 @@ var BpmnAdapter = /** @class */ (function () {
|
|
|
493
667
|
};
|
|
494
668
|
return bpmnData;
|
|
495
669
|
};
|
|
670
|
+
/**
|
|
671
|
+
* adapterIn:将 BPMN JSON 转换为 LogicFlow 图数据
|
|
672
|
+
* 输入:bpmnData:BPMN JSON
|
|
673
|
+
* 输出:GraphConfigData(nodes/edges)
|
|
674
|
+
*/
|
|
496
675
|
this.adapterIn = function (bpmnData) {
|
|
497
676
|
if (bpmnData) {
|
|
498
677
|
return convertBpmn2LfData(bpmnData);
|
|
@@ -545,14 +724,44 @@ BpmnAdapter.shapeConfigMap.set(BpmnElements.USER, {
|
|
|
545
724
|
width: UserTaskConfig.width,
|
|
546
725
|
height: UserTaskConfig.height,
|
|
547
726
|
});
|
|
727
|
+
/**
|
|
728
|
+
* BpmnXmlAdapter:XML 适配器(继承 BpmnAdapter)
|
|
729
|
+
*
|
|
730
|
+
* 作用:处理 XML 输入/输出的适配,使用 xml2json/json2xml 完成格式转换。
|
|
731
|
+
* 特殊处理:在 XML 导入前对 name 属性的非法字符进行预处理转义,提升容错。
|
|
732
|
+
*/
|
|
548
733
|
var BpmnXmlAdapter = /** @class */ (function (_super) {
|
|
549
734
|
__extends(BpmnXmlAdapter, _super);
|
|
735
|
+
/**
|
|
736
|
+
* 构造函数
|
|
737
|
+
* - 覆盖 LogicFlow 的 adapterIn/adapterOut,使其面向 XML 输入与输出。
|
|
738
|
+
*/
|
|
550
739
|
function BpmnXmlAdapter(data) {
|
|
551
740
|
var _this = _super.call(this, data) || this;
|
|
741
|
+
/**
|
|
742
|
+
* adapterXmlIn:将 BPMN XML 转换为 LogicFlow 图数据
|
|
743
|
+
* 输入:bpmnData:XML 字符串或对象
|
|
744
|
+
* 步骤:
|
|
745
|
+
* 1) 若为字符串,先对 name 属性进行预处理转义;
|
|
746
|
+
* 2) 使用 lfXml2Json 转换为 BPMN JSON;
|
|
747
|
+
* 3) 调用基础 adapterIn 转换为 GraphData。
|
|
748
|
+
*/
|
|
552
749
|
_this.adapterXmlIn = function (bpmnData) {
|
|
553
|
-
var
|
|
750
|
+
var xmlStr = typeof bpmnData === 'string'
|
|
751
|
+
? _this.sanitizeNameAttributes(bpmnData)
|
|
752
|
+
: bpmnData;
|
|
753
|
+
var json = lfXml2Json(xmlStr);
|
|
554
754
|
return _this.adapterIn(json);
|
|
555
755
|
};
|
|
756
|
+
/**
|
|
757
|
+
* adapterXmlOut:将 LogicFlow 图数据转换为 BPMN XML
|
|
758
|
+
* 输入:
|
|
759
|
+
* - data:GraphData
|
|
760
|
+
* - retainedFields:保留属性字段
|
|
761
|
+
* 步骤:
|
|
762
|
+
* 1) 调用基础 adapterOut 生成 BPMN JSON;
|
|
763
|
+
* 2) 使用 lfJson2Xml 转为合法的 XML 字符串(包含属性与文本的转义)。
|
|
764
|
+
*/
|
|
556
765
|
_this.adapterXmlOut = function (data, retainedFields) {
|
|
557
766
|
var outData = _this.adapterOut(data, retainedFields);
|
|
558
767
|
return lfJson2Xml(outData);
|
|
@@ -562,6 +771,20 @@ var BpmnXmlAdapter = /** @class */ (function (_super) {
|
|
|
562
771
|
lf.adapterOut = _this.adapterXmlOut;
|
|
563
772
|
return _this;
|
|
564
773
|
}
|
|
774
|
+
// 预处理:修复属性值中非法的XML字符(仅针对 name 属性)
|
|
775
|
+
/**
|
|
776
|
+
* 预处理 XML:仅对 name 属性值进行非法字符转义(<, >, &),避免 DOM 解析失败。
|
|
777
|
+
* 注意:不影响已合法的实体(如 &),仅在属性值中生效,不修改其它内容。
|
|
778
|
+
*/
|
|
779
|
+
BpmnXmlAdapter.prototype.sanitizeNameAttributes = function (xml) {
|
|
780
|
+
return xml.replace(/name="([^"]*)"/g, function (_, val) {
|
|
781
|
+
var safe = val
|
|
782
|
+
.replace(/&(?!#?\w+;)/g, '&')
|
|
783
|
+
.replace(/</g, '<')
|
|
784
|
+
.replace(/>/g, '>');
|
|
785
|
+
return "name=\"".concat(safe, "\"");
|
|
786
|
+
});
|
|
787
|
+
};
|
|
565
788
|
BpmnXmlAdapter.pluginName = 'bpmnXmlAdapter';
|
|
566
789
|
return BpmnXmlAdapter;
|
|
567
790
|
}(BpmnAdapter));
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
declare function handleAttributes(o: any): any;
|
|
2
|
+
/**
|
|
3
|
+
* 将普通文本中的一些特殊字符进行转移,保障文本安全地嵌入 XML:
|
|
4
|
+
* - 空值(`null/undefined`)返回空字符串,避免输出非法字面量;
|
|
5
|
+
* - 按顺序转义 XML 保留字符:`&`, `<`, `>`, `"`, `'`;
|
|
6
|
+
* 注意优先转义 `&`,避免后续生成的实体被再次转义。
|
|
7
|
+
* @param text 原始文本
|
|
8
|
+
* @returns 已完成 XML 转义的字符串
|
|
9
|
+
*/
|
|
10
|
+
declare function escapeXml(text: string): string;
|
|
2
11
|
/**
|
|
3
12
|
* json 转 xml
|
|
4
13
|
* @param o object
|
|
5
14
|
* @returns
|
|
6
15
|
*/
|
|
7
16
|
declare function lfJson2Xml(o: Object): string;
|
|
8
|
-
export { lfJson2Xml, handleAttributes };
|
|
17
|
+
export { lfJson2Xml, handleAttributes, escapeXml };
|
|
@@ -24,6 +24,29 @@ function handleAttributes(o) {
|
|
|
24
24
|
}
|
|
25
25
|
return t;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* 将普通文本中的一些特殊字符进行转移,保障文本安全地嵌入 XML:
|
|
29
|
+
* - 空值(`null/undefined`)返回空字符串,避免输出非法字面量;
|
|
30
|
+
* - 按顺序转义 XML 保留字符:`&`, `<`, `>`, `"`, `'`;
|
|
31
|
+
* 注意优先转义 `&`,避免后续生成的实体被再次转义。
|
|
32
|
+
* @param text 原始文本
|
|
33
|
+
* @returns 已完成 XML 转义的字符串
|
|
34
|
+
*/
|
|
35
|
+
function escapeXml(text) {
|
|
36
|
+
// 空值直接返回空字符串,防止在 XML 中出现 "null"/"undefined"
|
|
37
|
+
if (text == null)
|
|
38
|
+
return '';
|
|
39
|
+
return (text
|
|
40
|
+
.toString()
|
|
41
|
+
// & 必须先转义,避免影响后续 < > " ' 的实体
|
|
42
|
+
.replace(/&/g, '&')
|
|
43
|
+
// 小于号与大于号,用于标签边界
|
|
44
|
+
.replace(/</g, '<')
|
|
45
|
+
.replace(/>/g, '>')
|
|
46
|
+
// 双引号与单引号,用于属性值的包裹
|
|
47
|
+
.replace(/"/g, '"')
|
|
48
|
+
.replace(/'/g, '''));
|
|
49
|
+
}
|
|
27
50
|
function getAttributes(obj) {
|
|
28
51
|
var tmp = obj;
|
|
29
52
|
try {
|
|
@@ -34,7 +57,8 @@ function getAttributes(obj) {
|
|
|
34
57
|
catch (error) {
|
|
35
58
|
tmp = JSON.stringify(handleAttributes(obj)).replace(/"/g, "'");
|
|
36
59
|
}
|
|
37
|
-
|
|
60
|
+
// 确保属性值中的特殊字符被正确转义
|
|
61
|
+
return escapeXml(String(tmp));
|
|
38
62
|
}
|
|
39
63
|
var tn = '\t\n';
|
|
40
64
|
// @see issue https://github.com/didi/LogicFlow/issues/718, refactoring of function toXml
|
|
@@ -46,7 +70,7 @@ function toXml(obj, name, depth) {
|
|
|
46
70
|
}
|
|
47
71
|
var str = '';
|
|
48
72
|
if (name === '#text') {
|
|
49
|
-
return tn + frontSpace + obj;
|
|
73
|
+
return tn + frontSpace + escapeXml(String(obj));
|
|
50
74
|
}
|
|
51
75
|
else if (name === '#cdata-section') {
|
|
52
76
|
return tn + frontSpace + '<![CDATA[' + obj + ']]>';
|
|
@@ -78,7 +102,7 @@ function toXml(obj, name, depth) {
|
|
|
78
102
|
(children_1 !== '' ? ">".concat(children_1).concat(tn + frontSpace, "</").concat(name, ">") : ' />');
|
|
79
103
|
}
|
|
80
104
|
else {
|
|
81
|
-
str += tn + frontSpace + "<".concat(name, ">").concat(obj
|
|
105
|
+
str += tn + frontSpace + "<".concat(name, ">").concat(escapeXml(String(obj)), "</").concat(name, ">");
|
|
82
106
|
}
|
|
83
107
|
}
|
|
84
108
|
return str;
|
|
@@ -95,4 +119,4 @@ function lfJson2Xml(o) {
|
|
|
95
119
|
}
|
|
96
120
|
return xmlStr;
|
|
97
121
|
}
|
|
98
|
-
export { lfJson2Xml, handleAttributes };
|
|
122
|
+
export { lfJson2Xml, handleAttributes, escapeXml };
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// ========================================================================
|
|
3
3
|
// XML.ObjTree -- XML source code from/to JavaScript object like E4X
|
|
4
4
|
// ========================================================================
|
|
5
|
+
import { escapeXml } from './json2xml';
|
|
5
6
|
var XML = function () { };
|
|
6
7
|
// constructor
|
|
7
8
|
XML.ObjTree = function () {
|
|
@@ -290,13 +291,7 @@ XML.ObjTree.prototype.scalar_to_xml = function (name, text) {
|
|
|
290
291
|
}
|
|
291
292
|
};
|
|
292
293
|
// method: xml_escape( text )
|
|
293
|
-
XML.ObjTree.prototype.xml_escape =
|
|
294
|
-
return text
|
|
295
|
-
.replace(/&/g, '&')
|
|
296
|
-
.replace(/</g, '<')
|
|
297
|
-
.replace(/>/g, '>')
|
|
298
|
-
.replace(/"/g, '"');
|
|
299
|
-
};
|
|
294
|
+
XML.ObjTree.prototype.xml_escape = escapeXml;
|
|
300
295
|
/*
|
|
301
296
|
// ========================================================================
|
|
302
297
|
|
|
@@ -95,8 +95,10 @@ var MiniMap = /** @class */ (function () {
|
|
|
95
95
|
*/
|
|
96
96
|
this.show = function (left, top) {
|
|
97
97
|
if (!_this.isShow) {
|
|
98
|
+
_this.initMiniMap();
|
|
99
|
+
_this.lf.on('graph:resize', _this.onGraphResize);
|
|
98
100
|
_this.createMiniMap(left, top);
|
|
99
|
-
_this.setView();
|
|
101
|
+
_this.setView(true);
|
|
100
102
|
}
|
|
101
103
|
_this.isShow = true;
|
|
102
104
|
};
|
|
@@ -105,6 +107,13 @@ var MiniMap = /** @class */ (function () {
|
|
|
105
107
|
*/
|
|
106
108
|
this.hide = function () {
|
|
107
109
|
if (_this.isShow) {
|
|
110
|
+
// 隐藏小地图时摧毁实例
|
|
111
|
+
destroyTeleportContainer(_this.lfMap.graphModel.flowId);
|
|
112
|
+
_this.lf.off('graph:resize', _this.onGraphResize);
|
|
113
|
+
_this.lfMap.destroy();
|
|
114
|
+
// 保证重新创建实例时,小地图中内容偏移正确
|
|
115
|
+
_this.translateX = 0;
|
|
116
|
+
_this.translateY = 0;
|
|
108
117
|
_this.removeMiniMap();
|
|
109
118
|
_this.lf.emit('miniMap:close', {});
|
|
110
119
|
}
|
|
@@ -233,8 +242,6 @@ var MiniMap = /** @class */ (function () {
|
|
|
233
242
|
this.bounds = boundsInit;
|
|
234
243
|
this.elementAreaBounds = boundsInit;
|
|
235
244
|
this.viewPortBounds = boundsInit;
|
|
236
|
-
this.initMiniMap();
|
|
237
|
-
lf.on('graph:resize', this.onGraphResize);
|
|
238
245
|
}
|
|
239
246
|
/**
|
|
240
247
|
* 初始化小地图的配置
|