@dr2rai/raid-canvas 0.1.0 → 0.3.0

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.
@@ -0,0 +1,201 @@
1
+ /**
2
+ * @file semanticRules.ts
3
+ * @description Anti-entropy semantic connection validation and wiring rules
4
+ * for the AOAIM (Activity-Object-AI Model) graphical modeling contract.
5
+ *
6
+ * Enforces ontological integrity during edge creation:
7
+ * - 'per' -> 'uc' : 'association' («initiates», «owns» [0..1], «participates» [0..*])
8
+ * - 'per' -> 'act' : 'association' («executes»)
9
+ * - 'uc' -> 'uc' : 'dependency' («includes», «extends», «dependsOn»)
10
+ * - 'uc' -> 'act' : 'dependency' («includes»)
11
+ * - 'act' -> 'act' : 'association' («sequence» / process flow)
12
+ * - 'cls' -> 'cls' : 'association' («relatesTo»), 'generalization', 'composition', 'aggregation'
13
+ * - 'cls' -> 'obj' : 'dependency' («instantiates»)
14
+ * - 'obj' -> 'obj' : 'association' («link»)
15
+ */
16
+ /**
17
+ * Ontological connection rules matrix.
18
+ * Key: `${sourceKind}->${targetKind}`
19
+ */
20
+ export const SEMANTIC_RULES_MATRIX = {
21
+ 'per->uc': {
22
+ valid: true,
23
+ defaultEdgeKind: 'association',
24
+ defaultStereotype: '«initiates»',
25
+ description: 'Actor initiates, owns, or participates in UseCase',
26
+ availableStereotypes: [
27
+ {
28
+ stereotype: '«initiates»',
29
+ defaultCardinality: '1',
30
+ description: 'Initiating role triggering the UseCase flow',
31
+ },
32
+ {
33
+ stereotype: '«owns»',
34
+ defaultCardinality: '0..1',
35
+ description: 'Ownership relationship representing responsible party (cardinality 0..1)',
36
+ },
37
+ {
38
+ stereotype: '«participates»',
39
+ defaultCardinality: '0..*',
40
+ description: 'Participating role supporting the UseCase execution (cardinality 0..*)',
41
+ },
42
+ ],
43
+ },
44
+ 'per->act': {
45
+ valid: true,
46
+ defaultEdgeKind: 'association',
47
+ defaultStereotype: '«executes»',
48
+ description: 'Actor directly performs or executes Activity',
49
+ availableStereotypes: [
50
+ {
51
+ stereotype: '«executes»',
52
+ description: 'Actor performs this process step',
53
+ },
54
+ {
55
+ stereotype: '«approves»',
56
+ description: 'Actor reviews or approves activity completion',
57
+ },
58
+ ],
59
+ },
60
+ 'uc->uc': {
61
+ valid: true,
62
+ defaultEdgeKind: 'dependency',
63
+ defaultStereotype: '«includes»',
64
+ description: 'UseCase includes or extends sub-UseCase',
65
+ availableStereotypes: [
66
+ {
67
+ stereotype: '«includes»',
68
+ description: 'Mandatory sub-flow inclusion dependency',
69
+ },
70
+ {
71
+ stereotype: '«extends»',
72
+ description: 'Optional conditional extension point',
73
+ },
74
+ {
75
+ stereotype: '«dependsOn»',
76
+ description: 'Prerequisite functional dependency',
77
+ },
78
+ ],
79
+ },
80
+ 'uc->act': {
81
+ valid: true,
82
+ defaultEdgeKind: 'dependency',
83
+ defaultStereotype: '«includes»',
84
+ description: 'UseCase elaborates downflow process Activity',
85
+ availableStereotypes: [
86
+ {
87
+ stereotype: '«includes»',
88
+ description: 'Process activity required by UseCase',
89
+ },
90
+ {
91
+ stereotype: '«triggers»',
92
+ description: 'UseCase execution triggers activity',
93
+ },
94
+ ],
95
+ },
96
+ 'act->act': {
97
+ valid: true,
98
+ defaultEdgeKind: 'association',
99
+ defaultStereotype: '«sequence»',
100
+ description: 'Activity transitions to next process step',
101
+ availableStereotypes: [
102
+ {
103
+ stereotype: '«sequence»',
104
+ description: 'Sequential process transition',
105
+ },
106
+ {
107
+ stereotype: '«branch»',
108
+ description: 'Conditional decision branch',
109
+ },
110
+ ],
111
+ },
112
+ 'cls->cls': {
113
+ valid: true,
114
+ defaultEdgeKind: 'association',
115
+ defaultStereotype: '«relatesTo»',
116
+ description: 'Domain structural relationship between Classes',
117
+ availableStereotypes: [
118
+ {
119
+ stereotype: '«relatesTo»',
120
+ defaultCardinality: '1..*',
121
+ description: 'General domain association',
122
+ },
123
+ {
124
+ stereotype: '«generalization»',
125
+ description: 'Inheritance classification (subclass is-a superclass)',
126
+ },
127
+ {
128
+ stereotype: '«composition»',
129
+ defaultCardinality: '1',
130
+ description: 'Composite whole-part lifecycle binding',
131
+ },
132
+ {
133
+ stereotype: '«aggregation»',
134
+ defaultCardinality: '0..*',
135
+ description: 'Shared aggregation relationship',
136
+ },
137
+ ],
138
+ },
139
+ 'cls->obj': {
140
+ valid: true,
141
+ defaultEdgeKind: 'dependency',
142
+ defaultStereotype: '«instantiates»',
143
+ description: 'Class specifies runtime Object instance',
144
+ availableStereotypes: [
145
+ {
146
+ stereotype: '«instantiates»',
147
+ description: 'Class defines schema for runtime instance',
148
+ },
149
+ ],
150
+ },
151
+ 'obj->obj': {
152
+ valid: true,
153
+ defaultEdgeKind: 'association',
154
+ defaultStereotype: '«link»',
155
+ description: 'Runtime communication link between Objects',
156
+ availableStereotypes: [
157
+ {
158
+ stereotype: '«link»',
159
+ description: 'Runtime object collaboration message link',
160
+ },
161
+ ],
162
+ },
163
+ };
164
+ /**
165
+ * Validates whether an edge connection between source and target archetypes is ontologically allowed.
166
+ */
167
+ export function validateSemanticConnection(sourceKind, targetKind) {
168
+ if (!sourceKind || !targetKind)
169
+ return false;
170
+ const key = `${sourceKind}->${targetKind}`;
171
+ return SEMANTIC_RULES_MATRIX[key]?.valid ?? false;
172
+ }
173
+ /**
174
+ * Determines the canonical default relationship edge kind for a connected pair.
175
+ */
176
+ export function getSemanticEdgeKind(sourceKind, targetKind) {
177
+ const key = `${sourceKind}->${targetKind}`;
178
+ return SEMANTIC_RULES_MATRIX[key]?.defaultEdgeKind ?? 'association';
179
+ }
180
+ /**
181
+ * Determines the canonical default stereotype annotation for a connected pair.
182
+ */
183
+ export function getSemanticEdgeStereotype(sourceKind, targetKind) {
184
+ const key = `${sourceKind}->${targetKind}`;
185
+ return SEMANTIC_RULES_MATRIX[key]?.defaultStereotype ?? '';
186
+ }
187
+ /**
188
+ * Returns available ontological stereotypes and their default cardinalities for a pair.
189
+ */
190
+ export function getAvailableStereotypes(sourceKind, targetKind) {
191
+ const key = `${sourceKind}->${targetKind}`;
192
+ return SEMANTIC_RULES_MATRIX[key]?.availableStereotypes ?? [];
193
+ }
194
+ /**
195
+ * Returns a human-readable description explaining the ontological relationship.
196
+ */
197
+ export function getSemanticRuleDescription(sourceKind, targetKind) {
198
+ const key = `${sourceKind}->${targetKind}`;
199
+ return SEMANTIC_RULES_MATRIX[key]?.description ?? 'Invalid ontological connection';
200
+ }
201
+ //# sourceMappingURL=semanticRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semanticRules.js","sourceRoot":"","sources":["../src/semanticRules.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -15,7 +15,14 @@
15
15
  * - 'obj' : Object / Instance (runtime instance card with underlined title)
16
16
  * - 'per' : Person / Actor (Initiating or Defined role stick-figure/card)
17
17
  */
18
- export type AimOntologyKind = 'uc' | 'act' | 'cls' | 'obj' | 'per';
18
+ export type AimOntologyKind = 'act' | 'uc' | 'cls' | 'obj' | 'per';
19
+ /**
20
+ * Routing strategy for diagram edges.
21
+ * - 'manhattan': Obstacle-avoiding 90° orthogonal routing with rounded corners (default).
22
+ * - 'normal': Direct straight line point-to-point connection.
23
+ * - 'smooth': Curved cubic bezier spline between ports.
24
+ */
25
+ export type AimRoutingMode = 'manhattan' | 'normal' | 'smooth';
19
26
  /**
20
27
  * Ontological relationship classifications in AOAIM.
21
28
  */
@@ -94,6 +101,8 @@ export interface RaidEdgeData {
94
101
  readonly sourceCardinality?: string;
95
102
  /** Multiplicity / Cardinality at the target end (e.g., '0..1', '*'). */
96
103
  readonly targetCardinality?: string;
104
+ /** Routing strategy for this edge ('manhattan', 'normal', 'smooth'). */
105
+ readonly routing?: AimRoutingMode;
97
106
  /** User-editable or router-computed Manhattan bend points. */
98
107
  readonly bendPoints: readonly SvgBendPoint[];
99
108
  }
@@ -130,6 +139,7 @@ export declare const AimSvgContract: {
130
139
  readonly ATTR_TARGET: 'aim-target';
131
140
  readonly ATTR_SOURCE_PORT: 'aim-source-port';
132
141
  readonly ATTR_TARGET_PORT: 'aim-target-port';
142
+ readonly ATTR_ROUTING: 'aim-routing';
133
143
  readonly ATTR_BENDS: 'aim-bends';
134
144
  readonly SELECTOR_NODE: '[aim-node], [data-node], g[aim-kind]';
135
145
  readonly SELECTOR_EDGE: '[aim-edge], path[aim-edge-kind]';
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -24,6 +24,7 @@ export const AimSvgContract = {
24
24
  ATTR_TARGET: 'aim-target',
25
25
  ATTR_SOURCE_PORT: 'aim-source-port',
26
26
  ATTR_TARGET_PORT: 'aim-target-port',
27
+ ATTR_ROUTING: 'aim-routing',
27
28
  ATTR_BENDS: 'aim-bends',
28
29
  // Selectors for DOM queries
29
30
  SELECTOR_NODE: '[aim-node], [data-node], g[aim-kind]',
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAoJH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,4BAA4B;IAC5B,SAAS,EAAE,UAAU;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,UAAU;IACrB,iBAAiB,EAAE,kBAAkB;IACrC,eAAe,EAAE,gBAAgB;IACjC,cAAc,EAAE,eAAe;IAE/B,4BAA4B;IAC5B,SAAS,EAAE,UAAU;IACrB,cAAc,EAAE,eAAe;IAC/B,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,iBAAiB;IACnC,gBAAgB,EAAE,iBAAiB;IACnC,UAAU,EAAE,WAAW;IAEvB,4BAA4B;IAC5B,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,iCAAiC;CACxC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA+JH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,4BAA4B;IAC5B,SAAS,EAAE,UAAU;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,UAAU;IACrB,iBAAiB,EAAE,kBAAkB;IACrC,eAAe,EAAE,gBAAgB;IACjC,cAAc,EAAE,eAAe;IAE/B,4BAA4B;IAC5B,SAAS,EAAE,UAAU;IACrB,cAAc,EAAE,eAAe;IAC/B,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,iBAAiB;IACnC,gBAAgB,EAAE,iBAAiB;IACnC,YAAY,EAAE,aAAa;IAC3B,UAAU,EAAE,WAAW;IAEvB,4BAA4B;IAC5B,aAAa,EAAE,sCAAsC;IACrD,aAAa,EAAE,iCAAiC;CACxC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dr2rai/raid-canvas",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Interactive AntV X6 diagram canvas for AOAIM (.raid) models and ontological SVG contracts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,16 @@
25
25
  "dependencies": {
26
26
  "@antv/x6": "^2.18.1"
27
27
  },
28
+ "peerDependencies": {
29
+ "react": "^18.0.0 || ^19.0.0",
30
+ "react-dom": "^18.0.0 || ^19.0.0"
31
+ },
28
32
  "devDependencies": {
29
33
  "@types/node": "^22.5.5",
34
+ "@types/react": "^19.0.0",
35
+ "@types/react-dom": "^19.0.0",
36
+ "react": "^19.0.0",
37
+ "react-dom": "^19.0.0",
30
38
  "typescript": "^7.0.2"
31
39
  },
32
40
  "publishConfig": {
@@ -37,6 +45,6 @@
37
45
  "scripts": {
38
46
  "build": "tsc -b --force",
39
47
  "typecheck": "tsc --noEmit",
40
- "test": "node --test test/canvas.test.mjs"
48
+ "test": "node --test test/canvas.test.mjs test/RaidCanvas.test.mjs test/semanticRules.test.mjs"
41
49
  }
42
50
  }
package/src/RaiBridge.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  AimSvgContract,
16
16
  type AimOntologyKind,
17
17
  type AimEdgeKind,
18
+ type AimRoutingMode,
18
19
  type RaidNodeData,
19
20
  type RaidEdgeData,
20
21
  type RaidMetamodel,
@@ -138,6 +139,21 @@ export class RaiBridge {
138
139
  const targetPort = edge.getTargetPortId();
139
140
  const label = (edge.getLabels()?.[0]?.attrs?.['text']?.['text'] as string | undefined) ?? customData.label;
140
141
 
142
+ let routing: AimRoutingMode | undefined = customData.routing;
143
+ if (!routing) {
144
+ const router = edge.getRouter();
145
+ const routerName = typeof router === 'string' ? router : router?.name;
146
+ const connector = edge.getConnector();
147
+ const connectorName = typeof connector === 'string' ? connector : connector?.name;
148
+ if (connectorName === 'smooth') {
149
+ routing = 'smooth';
150
+ } else if (routerName === 'normal') {
151
+ routing = 'normal';
152
+ } else if (routerName === 'manhattan') {
153
+ routing = 'manhattan';
154
+ }
155
+ }
156
+
141
157
  const edgeData: RaidEdgeData = {
142
158
  id: edge.id,
143
159
  kind: customData.kind ?? 'association',
@@ -145,8 +161,11 @@ export class RaiBridge {
145
161
  targetId: target.id,
146
162
  ...(sourcePort !== undefined ? { sourcePort } : {}),
147
163
  ...(targetPort !== undefined ? { targetPort } : {}),
164
+ ...(routing !== undefined ? { routing } : {}),
148
165
  ...(label !== undefined ? { label } : {}),
149
166
  ...(customData.stereotype !== undefined ? { stereotype: customData.stereotype } : {}),
167
+ ...(customData.sourceCardinality !== undefined ? { sourceCardinality: customData.sourceCardinality } : {}),
168
+ ...(customData.targetCardinality !== undefined ? { targetCardinality: customData.targetCardinality } : {}),
150
169
  bendPoints,
151
170
  };
152
171
 
@@ -266,8 +285,74 @@ export class RaiBridge {
266
285
  const bendsAttr = el.getAttribute(AimSvgContract.ATTR_BENDS) ?? '';
267
286
  const bendPoints = this.parseBendPoints(bendsAttr);
268
287
 
269
- const sourcePort = el.getAttribute(AimSvgContract.ATTR_SOURCE_PORT) ?? undefined;
270
- const targetPort = el.getAttribute(AimSvgContract.ATTR_TARGET_PORT) ?? undefined;
288
+ const label =
289
+ el.getAttribute('aim-label') ??
290
+ el.querySelector('text')?.textContent?.trim() ??
291
+ undefined;
292
+
293
+ let sourcePort = el.getAttribute(AimSvgContract.ATTR_SOURCE_PORT) ?? undefined;
294
+ let targetPort = el.getAttribute(AimSvgContract.ATTR_TARGET_PORT) ?? undefined;
295
+
296
+ const sourceNode = nodes.find((n) => n.id === sourceId);
297
+ const targetNode = nodes.find((n) => n.id === targetId);
298
+
299
+ // Infer optimal orthogonal docking ports if not explicitly declared
300
+ if (sourceNode && targetNode) {
301
+ const dx =
302
+ targetNode.bounds.x +
303
+ targetNode.bounds.width / 2 -
304
+ (sourceNode.bounds.x + sourceNode.bounds.width / 2);
305
+ const dy =
306
+ targetNode.bounds.y +
307
+ targetNode.bounds.height / 2 -
308
+ (sourceNode.bounds.y + sourceNode.bounds.height / 2);
309
+
310
+ if (!sourcePort) {
311
+ sourcePort =
312
+ Math.abs(dx) >= Math.abs(dy)
313
+ ? dx >= 0
314
+ ? 'port-right'
315
+ : 'port-left'
316
+ : dy >= 0
317
+ ? 'port-bottom'
318
+ : 'port-top';
319
+ }
320
+ if (!targetPort) {
321
+ targetPort =
322
+ Math.abs(dx) >= Math.abs(dy)
323
+ ? dx >= 0
324
+ ? 'port-left'
325
+ : 'port-right'
326
+ : dy >= 0
327
+ ? 'port-top'
328
+ : 'port-bottom';
329
+ }
330
+ }
331
+
332
+ // If bendPoints contains only the 2 terminal endpoints of a straight connector,
333
+ // clear them so the orthogonal router doesn't treat the terminals as obstacle waypoints
334
+ const isTerminalOnly =
335
+ bendPoints.length === 2 &&
336
+ sourceNode &&
337
+ targetNode &&
338
+ ((Math.abs(bendPoints[0]!.y - bendPoints[1]!.y) < 2 &&
339
+ Math.abs(bendPoints[0]!.y - (sourceNode.bounds.y + sourceNode.bounds.height / 2)) < 40) ||
340
+ (Math.abs(bendPoints[0]!.x - bendPoints[1]!.x) < 2 &&
341
+ Math.abs(bendPoints[0]!.x - (sourceNode.bounds.x + sourceNode.bounds.width / 2)) < 40));
342
+ const effectiveBendPoints = isTerminalOnly ? [] : bendPoints;
343
+
344
+ const sourceCardinality =
345
+ el.getAttribute('aim-source-cardinality') ?? undefined;
346
+ const targetCardinality =
347
+ el.getAttribute('aim-target-cardinality') ?? undefined;
348
+ const rawRouting =
349
+ el.getAttribute(AimSvgContract.ATTR_ROUTING) ??
350
+ el.getAttribute('aim-routing') ??
351
+ undefined;
352
+ const routing =
353
+ rawRouting === 'normal' || rawRouting === 'smooth' || rawRouting === 'manhattan'
354
+ ? (rawRouting as AimRoutingMode)
355
+ : undefined;
271
356
 
272
357
  edges.push({
273
358
  id,
@@ -276,7 +361,11 @@ export class RaiBridge {
276
361
  targetId,
277
362
  ...(sourcePort !== undefined ? { sourcePort } : {}),
278
363
  ...(targetPort !== undefined ? { targetPort } : {}),
279
- bendPoints,
364
+ ...(routing !== undefined ? { routing } : {}),
365
+ ...(label !== undefined ? { label } : {}),
366
+ ...(sourceCardinality !== undefined ? { sourceCardinality } : {}),
367
+ ...(targetCardinality !== undefined ? { targetCardinality } : {}),
368
+ bendPoints: effectiveBendPoints,
280
369
  });
281
370
  }
282
371
 
@@ -370,6 +459,30 @@ export class RaiBridge {
370
459
  el.setAttribute(AimSvgContract.ATTR_BENDS, bendsString);
371
460
  el.setAttribute(AimSvgContract.ATTR_EDGE, 'true');
372
461
  el.setAttribute(AimSvgContract.ATTR_EDGE_KIND, edge.kind);
462
+ if (edge.sourceId !== undefined) {
463
+ el.setAttribute(AimSvgContract.ATTR_SOURCE, edge.sourceId);
464
+ }
465
+ if (edge.targetId !== undefined) {
466
+ el.setAttribute(AimSvgContract.ATTR_TARGET, edge.targetId);
467
+ }
468
+ if (edge.sourcePort !== undefined) {
469
+ el.setAttribute(AimSvgContract.ATTR_SOURCE_PORT, edge.sourcePort);
470
+ }
471
+ if (edge.targetPort !== undefined) {
472
+ el.setAttribute(AimSvgContract.ATTR_TARGET_PORT, edge.targetPort);
473
+ }
474
+ if (edge.routing !== undefined) {
475
+ el.setAttribute(AimSvgContract.ATTR_ROUTING, edge.routing);
476
+ }
477
+ if (edge.stereotype !== undefined) {
478
+ el.setAttribute(AimSvgContract.ATTR_STEREOTYPE, edge.stereotype);
479
+ }
480
+ if (edge.sourceCardinality !== undefined) {
481
+ el.setAttribute('aim-source-cardinality', edge.sourceCardinality);
482
+ }
483
+ if (edge.targetCardinality !== undefined) {
484
+ el.setAttribute('aim-target-cardinality', edge.targetCardinality);
485
+ }
373
486
  }
374
487
  }
375
488
 
@@ -415,7 +528,11 @@ export class RaiBridge {
415
528
  pathD = `M ${first.x} ${first.y} ` + edge.bendPoints.slice(1).map((p) => `L ${p.x} ${p.y}`).join(' ');
416
529
  }
417
530
 
418
- svg += ` <g ${AimSvgContract.ATTR_EDGE}="true" ${AimSvgContract.ATTR_ID}="${edge.id}" ${AimSvgContract.ATTR_EDGE_KIND}="${edge.kind}" ${AimSvgContract.ATTR_SOURCE}="${edge.sourceId}" ${AimSvgContract.ATTR_TARGET}="${edge.targetId}" ${AimSvgContract.ATTR_BENDS}="${bendsFormatted}">\n`;
531
+ const sourcePortAttr = edge.sourcePort ? ` ${AimSvgContract.ATTR_SOURCE_PORT}="${edge.sourcePort}"` : '';
532
+ const targetPortAttr = edge.targetPort ? ` ${AimSvgContract.ATTR_TARGET_PORT}="${edge.targetPort}"` : '';
533
+ const routingAttr = edge.routing ? ` ${AimSvgContract.ATTR_ROUTING}="${edge.routing}"` : '';
534
+
535
+ svg += ` <g ${AimSvgContract.ATTR_EDGE}="true" ${AimSvgContract.ATTR_ID}="${edge.id}" ${AimSvgContract.ATTR_EDGE_KIND}="${edge.kind}" ${AimSvgContract.ATTR_SOURCE}="${edge.sourceId}" ${AimSvgContract.ATTR_TARGET}="${edge.targetId}"${sourcePortAttr}${targetPortAttr}${routingAttr} ${AimSvgContract.ATTR_BENDS}="${bendsFormatted}">\n`;
419
536
  if (pathD) {
420
537
  svg += ` <path d="${pathD}" class="aim-edge"${strokeDash}${markerEnd} />\n`;
421
538
  }