@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.
@@ -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转换为普通的json,在内部使用。
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
+ * 注意:不影响已合法的实体(如 &amp;),仅在属性值中生效,不修改其它内容。
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 };
@@ -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 实体还原为字符:`&lt;`→`<`、`&gt;`→`>`、`&amp;`→`&`、`&quot;`→`"`、`&apos;`→`'`;保障流程图能正常回填
108
+ * - 使用 `String(text || '')` 规范化输入,避免 `null/undefined` 导致错误;
109
+ * - 注意:此实现为单次替换,若存在嵌套/二次编码(例如 `&amp;lt;`),会先还原为 `&lt;`,
110
+ * 如需完全解码,可在外层循环调用或调整替换顺序策略。
111
+ */
112
+ var unescapeXml = function (text) {
113
+ return String(text || '')
114
+ .replace(/&lt;/g, '<')
115
+ .replace(/&gt;/g, '>')
116
+ .replace(/&amp;/g, '&')
117
+ .replace(/&quot;/g, '"')
118
+ .replace(/&apos;/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转换为普通的json,在内部使用。
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 bpmnEdges = definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNEdge'];
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 shapes = definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNShape'];
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
- var name = processValue['-name'];
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
- var textVal = processValue['-name'] ? "".concat(processValue['-name']) : '';
555
+ // 反转义 XML 实体,确保导入后文本包含特殊字符时能被完整还原
556
+ var textVal = processValue['-name']
557
+ ? unescapeXml("".concat(processValue['-name']))
558
+ : '';
424
559
  if (textVal) {
425
- var textBounds = edgeValue['bpmndi:BPMNLabel']['dc:Bounds'];
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
- text = {
434
- value: textVal,
435
- x: Number(textBounds['-x']) + (textLength_1 * 10) / 2,
436
- y: Number(textBounds['-y']) + 7,
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 json = lfXml2Json(bpmnData);
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
+ * 注意:不影响已合法的实体(如 &amp;),仅在属性值中生效,不修改其它内容。
778
+ */
779
+ BpmnXmlAdapter.prototype.sanitizeNameAttributes = function (xml) {
780
+ return xml.replace(/name="([^"]*)"/g, function (_, val) {
781
+ var safe = val
782
+ .replace(/&(?!#?\w+;)/g, '&amp;')
783
+ .replace(/</g, '&lt;')
784
+ .replace(/>/g, '&gt;');
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, '&amp;')
43
+ // 小于号与大于号,用于标签边界
44
+ .replace(/</g, '&lt;')
45
+ .replace(/>/g, '&gt;')
46
+ // 双引号与单引号,用于属性值的包裹
47
+ .replace(/"/g, '&quot;')
48
+ .replace(/'/g, '&apos;'));
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
- return tmp;
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.toString(), "</").concat(name, ">");
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 = function (text) {
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
  * 初始化小地图的配置