@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.
- package/dist/RaiBridge.d.ts.map +1 -1
- package/dist/RaiBridge.js +106 -4
- package/dist/RaiBridge.js.map +1 -1
- package/dist/RaidCanvas.d.ts +82 -0
- package/dist/RaidCanvas.d.ts.map +1 -0
- package/dist/RaidCanvas.js +748 -0
- package/dist/RaidCanvas.js.map +1 -0
- package/dist/X6Shapes.d.ts +16 -1
- package/dist/X6Shapes.d.ts.map +1 -1
- package/dist/X6Shapes.js +107 -18
- package/dist/X6Shapes.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/semanticRules.d.ts +55 -0
- package/dist/semanticRules.d.ts.map +1 -0
- package/dist/semanticRules.js +201 -0
- package/dist/semanticRules.js.map +1 -0
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +10 -2
- package/src/RaiBridge.ts +121 -4
- package/src/RaidCanvas.tsx +999 -0
- package/src/X6Shapes.ts +119 -18
- package/src/index.ts +25 -0
- package/src/semanticRules.ts +237 -0
- package/src/types.ts +13 -1
package/src/X6Shapes.ts
CHANGED
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
* - Cascais Heraldry design tokens.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { Graph, Node, Edge } from '@antv/x6';
|
|
12
|
+
import { Graph, Shape, Node, Edge } from '@antv/x6';
|
|
13
13
|
import type {
|
|
14
|
+
AimOntologyKind,
|
|
14
15
|
AimEdgeKind,
|
|
16
|
+
AimRoutingMode,
|
|
15
17
|
RaidNodeData,
|
|
16
18
|
RaidEdgeData,
|
|
17
19
|
OrthogonalPortId,
|
|
20
|
+
Bounds,
|
|
18
21
|
} from './types.js';
|
|
19
22
|
|
|
20
23
|
/**
|
|
@@ -105,9 +108,9 @@ export function registerAimShapes(): void {
|
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
// 1. AimUseCaseNode ('uc') — Ellipse with Net Gold border
|
|
108
|
-
|
|
111
|
+
Shape.Ellipse.define({
|
|
109
112
|
shape: 'aim-uc',
|
|
110
|
-
|
|
113
|
+
overwrite: true,
|
|
111
114
|
width: 140,
|
|
112
115
|
height: 70,
|
|
113
116
|
attrs: {
|
|
@@ -115,8 +118,6 @@ export function registerAimShapes(): void {
|
|
|
115
118
|
fill: CascaisPalette.ChalkWhite,
|
|
116
119
|
stroke: CascaisPalette.NetGold,
|
|
117
120
|
strokeWidth: 2,
|
|
118
|
-
rx: 70,
|
|
119
|
-
ry: 35,
|
|
120
121
|
class: 'aim-node aim-uc',
|
|
121
122
|
},
|
|
122
123
|
label: {
|
|
@@ -133,9 +134,9 @@ export function registerAimShapes(): void {
|
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
// 2. AimActivityNode ('act') — Rounded rectangle with Heraldic Green border
|
|
136
|
-
|
|
137
|
+
Shape.Rect.define({
|
|
137
138
|
shape: 'aim-act',
|
|
138
|
-
|
|
139
|
+
overwrite: true,
|
|
139
140
|
width: 150,
|
|
140
141
|
height: 60,
|
|
141
142
|
attrs: {
|
|
@@ -161,9 +162,9 @@ export function registerAimShapes(): void {
|
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
// 3. AimClassNode ('cls') — Compartmentalized class card
|
|
164
|
-
|
|
165
|
+
Shape.Rect.define({
|
|
165
166
|
shape: 'aim-cls',
|
|
166
|
-
|
|
167
|
+
overwrite: true,
|
|
167
168
|
width: 180,
|
|
168
169
|
height: 100,
|
|
169
170
|
markup: [
|
|
@@ -258,9 +259,9 @@ export function registerAimShapes(): void {
|
|
|
258
259
|
});
|
|
259
260
|
|
|
260
261
|
// 4. AimObjectNode ('obj') — Instance card with underlined title
|
|
261
|
-
|
|
262
|
+
Shape.Rect.define({
|
|
262
263
|
shape: 'aim-obj',
|
|
263
|
-
|
|
264
|
+
overwrite: true,
|
|
264
265
|
width: 160,
|
|
265
266
|
height: 80,
|
|
266
267
|
attrs: {
|
|
@@ -271,7 +272,7 @@ export function registerAimShapes(): void {
|
|
|
271
272
|
class: 'aim-node aim-obj',
|
|
272
273
|
},
|
|
273
274
|
label: {
|
|
274
|
-
text: '
|
|
275
|
+
text: 'instance: Type',
|
|
275
276
|
fill: CascaisPalette.TextPrimary,
|
|
276
277
|
fontSize: 12,
|
|
277
278
|
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
|
|
@@ -283,9 +284,9 @@ export function registerAimShapes(): void {
|
|
|
283
284
|
});
|
|
284
285
|
|
|
285
286
|
// 5. AimPersonNode ('per') — Person / Actor role card
|
|
286
|
-
|
|
287
|
+
Shape.Rect.define({
|
|
287
288
|
shape: 'aim-per',
|
|
288
|
-
|
|
289
|
+
overwrite: true,
|
|
289
290
|
width: 120,
|
|
290
291
|
height: 70,
|
|
291
292
|
attrs: {
|
|
@@ -311,9 +312,9 @@ export function registerAimShapes(): void {
|
|
|
311
312
|
});
|
|
312
313
|
|
|
313
314
|
// 6. AimEdge — Orthogonal Manhattan edge with rounded corners
|
|
314
|
-
Edge.define({
|
|
315
|
+
Shape.Edge.define({
|
|
315
316
|
shape: 'aim-edge',
|
|
316
|
-
|
|
317
|
+
overwrite: true,
|
|
317
318
|
router: {
|
|
318
319
|
name: 'manhattan',
|
|
319
320
|
args: {
|
|
@@ -457,6 +458,34 @@ export function createAimNode(data: RaidNodeData): Node.Metadata {
|
|
|
457
458
|
}
|
|
458
459
|
}
|
|
459
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Configures the router and connector for an X6 Edge based on AimRoutingMode.
|
|
463
|
+
* - 'manhattan': Obstacle-avoiding 90° orthogonal router with rounded corners (radius: 8).
|
|
464
|
+
* - 'normal': Direct straight line point-to-point connection.
|
|
465
|
+
* - 'smooth': Curved cubic bezier spline between ports.
|
|
466
|
+
*/
|
|
467
|
+
export function applyEdgeRouting(edge: Edge, routing: AimRoutingMode = 'manhattan'): void {
|
|
468
|
+
switch (routing) {
|
|
469
|
+
case 'normal':
|
|
470
|
+
edge.setRouter('normal');
|
|
471
|
+
edge.setConnector('normal');
|
|
472
|
+
break;
|
|
473
|
+
case 'smooth':
|
|
474
|
+
edge.setRouter('normal');
|
|
475
|
+
edge.setConnector('smooth');
|
|
476
|
+
break;
|
|
477
|
+
case 'manhattan':
|
|
478
|
+
default:
|
|
479
|
+
edge.setRouter('manhattan', {
|
|
480
|
+
padding: 20,
|
|
481
|
+
startDirections: ['top', 'right', 'bottom', 'left'],
|
|
482
|
+
endDirections: ['top', 'right', 'bottom', 'left'],
|
|
483
|
+
});
|
|
484
|
+
edge.setConnector('rounded', { radius: 8 });
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
460
489
|
/**
|
|
461
490
|
* Factory creating an AntV X6 Edge model from a RaidEdgeData specification.
|
|
462
491
|
*/
|
|
@@ -464,10 +493,34 @@ export function createAimEdge(data: RaidEdgeData): Edge.Metadata {
|
|
|
464
493
|
registerAimShapes();
|
|
465
494
|
|
|
466
495
|
const edgeAttrs = getEdgeStyling(data.kind);
|
|
496
|
+
const routing = data.routing ?? 'manhattan';
|
|
497
|
+
|
|
498
|
+
let routerConfig: Edge.Metadata['router'] = {
|
|
499
|
+
name: 'manhattan',
|
|
500
|
+
args: {
|
|
501
|
+
padding: 20,
|
|
502
|
+
startDirections: ['top', 'right', 'bottom', 'left'],
|
|
503
|
+
endDirections: ['top', 'right', 'bottom', 'left'],
|
|
504
|
+
},
|
|
505
|
+
};
|
|
506
|
+
let connectorConfig: Edge.Metadata['connector'] = {
|
|
507
|
+
name: 'rounded',
|
|
508
|
+
args: { radius: 8 },
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
if (routing === 'normal') {
|
|
512
|
+
routerConfig = { name: 'normal' };
|
|
513
|
+
connectorConfig = { name: 'normal' };
|
|
514
|
+
} else if (routing === 'smooth') {
|
|
515
|
+
routerConfig = { name: 'normal' };
|
|
516
|
+
connectorConfig = { name: 'smooth' };
|
|
517
|
+
}
|
|
467
518
|
|
|
468
519
|
return {
|
|
469
520
|
id: data.id,
|
|
470
521
|
shape: 'aim-edge',
|
|
522
|
+
router: routerConfig,
|
|
523
|
+
connector: connectorConfig,
|
|
471
524
|
source: {
|
|
472
525
|
cell: data.sourceId,
|
|
473
526
|
...(data.sourcePort !== undefined ? { port: data.sourcePort } : {}),
|
|
@@ -509,8 +562,11 @@ function getEdgeStyling(kind: AimEdgeKind): Record<string, unknown> {
|
|
|
509
562
|
strokeWidth: 1.5,
|
|
510
563
|
strokeDasharray: '5,5',
|
|
511
564
|
targetMarker: {
|
|
512
|
-
name: '
|
|
513
|
-
|
|
565
|
+
name: 'block',
|
|
566
|
+
args: {
|
|
567
|
+
size: 8,
|
|
568
|
+
open: true,
|
|
569
|
+
},
|
|
514
570
|
},
|
|
515
571
|
};
|
|
516
572
|
|
|
@@ -573,3 +629,48 @@ function getEdgeStyling(kind: AimEdgeKind): Record<string, unknown> {
|
|
|
573
629
|
};
|
|
574
630
|
}
|
|
575
631
|
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Returns default Cartesian bounds for an instantiated AOAIM archetype.
|
|
635
|
+
*/
|
|
636
|
+
export function getDefaultNodeBounds(
|
|
637
|
+
kind: AimOntologyKind | string,
|
|
638
|
+
x: number = 100,
|
|
639
|
+
y: number = 100,
|
|
640
|
+
): Bounds {
|
|
641
|
+
switch (kind) {
|
|
642
|
+
case 'uc':
|
|
643
|
+
return { x, y, width: 140, height: 70 };
|
|
644
|
+
case 'act':
|
|
645
|
+
return { x, y, width: 150, height: 60 };
|
|
646
|
+
case 'cls':
|
|
647
|
+
return { x, y, width: 180, height: 110 };
|
|
648
|
+
case 'obj':
|
|
649
|
+
return { x, y, width: 160, height: 80 };
|
|
650
|
+
case 'per':
|
|
651
|
+
return { x, y, width: 120, height: 70 };
|
|
652
|
+
default:
|
|
653
|
+
return { x, y, width: 140, height: 60 };
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Returns a canonical default display name for an instantiated AOAIM archetype.
|
|
659
|
+
*/
|
|
660
|
+
export function getDefaultNodeName(kind: AimOntologyKind | string): string {
|
|
661
|
+
switch (kind) {
|
|
662
|
+
case 'uc':
|
|
663
|
+
return 'New UseCase';
|
|
664
|
+
case 'act':
|
|
665
|
+
return 'New Activity';
|
|
666
|
+
case 'cls':
|
|
667
|
+
return 'NewClass';
|
|
668
|
+
case 'obj':
|
|
669
|
+
return 'new Object';
|
|
670
|
+
case 'per':
|
|
671
|
+
return 'Actor';
|
|
672
|
+
default:
|
|
673
|
+
return 'Entity';
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
package/src/index.ts
CHANGED
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
* - 4-way orthogonal ports and Manhattan router integration.
|
|
8
8
|
* - Cascais Heraldry design tokens and theme styling.
|
|
9
9
|
* - Bidirectional RaiBridge for hydrating from and serializing to the aim-* SVG contract.
|
|
10
|
+
* - Anti-entropy semantic connection validation and wiring rules.
|
|
11
|
+
* - Reusable <RaidCanvas /> React component with Dnd and imperative control handle.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
// Core Metamodel & SVG Contract Types
|
|
13
15
|
export {
|
|
14
16
|
AimSvgContract,
|
|
15
17
|
type AimOntologyKind,
|
|
18
|
+
type AimRoutingMode,
|
|
16
19
|
type AimEdgeKind,
|
|
17
20
|
type Point,
|
|
18
21
|
type SvgBendPoint,
|
|
@@ -33,7 +36,29 @@ export {
|
|
|
33
36
|
configureAimGraph,
|
|
34
37
|
createAimNode,
|
|
35
38
|
createAimEdge,
|
|
39
|
+
applyEdgeRouting,
|
|
40
|
+
getDefaultNodeBounds,
|
|
41
|
+
getDefaultNodeName,
|
|
36
42
|
} from './X6Shapes.js';
|
|
37
43
|
|
|
44
|
+
// Anti-Entropy Semantic Connection Rules
|
|
45
|
+
export {
|
|
46
|
+
SEMANTIC_RULES_MATRIX,
|
|
47
|
+
validateSemanticConnection,
|
|
48
|
+
getSemanticEdgeKind,
|
|
49
|
+
getSemanticEdgeStereotype,
|
|
50
|
+
getSemanticRuleDescription,
|
|
51
|
+
getAvailableStereotypes,
|
|
52
|
+
type SemanticRule,
|
|
53
|
+
type StereotypeOption,
|
|
54
|
+
} from './semanticRules.js';
|
|
55
|
+
|
|
38
56
|
// Bidirectional SVG <-> X6 Synchronization Bridge
|
|
39
57
|
export { RaiBridge } from './RaiBridge.js';
|
|
58
|
+
|
|
59
|
+
// Reusable React Canvas Component & Ref Handle
|
|
60
|
+
export {
|
|
61
|
+
RaidCanvas,
|
|
62
|
+
type RaidCanvasProps,
|
|
63
|
+
type RaidCanvasHandle,
|
|
64
|
+
} from './RaidCanvas.js';
|
|
@@ -0,0 +1,237 @@
|
|
|
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
|
+
import type { AimOntologyKind, AimEdgeKind } from './types.js';
|
|
18
|
+
|
|
19
|
+
export interface StereotypeOption {
|
|
20
|
+
readonly stereotype: string;
|
|
21
|
+
readonly defaultCardinality?: string;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SemanticRule {
|
|
26
|
+
readonly valid: boolean;
|
|
27
|
+
readonly defaultEdgeKind: AimEdgeKind;
|
|
28
|
+
readonly defaultStereotype: string;
|
|
29
|
+
readonly defaultCardinality?: string;
|
|
30
|
+
readonly availableStereotypes: readonly StereotypeOption[];
|
|
31
|
+
readonly description: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Ontological connection rules matrix.
|
|
36
|
+
* Key: `${sourceKind}->${targetKind}`
|
|
37
|
+
*/
|
|
38
|
+
export const SEMANTIC_RULES_MATRIX: Readonly<Record<string, SemanticRule>> = {
|
|
39
|
+
'per->uc': {
|
|
40
|
+
valid: true,
|
|
41
|
+
defaultEdgeKind: 'association',
|
|
42
|
+
defaultStereotype: '«initiates»',
|
|
43
|
+
description: 'Actor initiates, owns, or participates in UseCase',
|
|
44
|
+
availableStereotypes: [
|
|
45
|
+
{
|
|
46
|
+
stereotype: '«initiates»',
|
|
47
|
+
defaultCardinality: '1',
|
|
48
|
+
description: 'Initiating role triggering the UseCase flow',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
stereotype: '«owns»',
|
|
52
|
+
defaultCardinality: '0..1',
|
|
53
|
+
description: 'Ownership relationship representing responsible party (cardinality 0..1)',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
stereotype: '«participates»',
|
|
57
|
+
defaultCardinality: '0..*',
|
|
58
|
+
description: 'Participating role supporting the UseCase execution (cardinality 0..*)',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
'per->act': {
|
|
63
|
+
valid: true,
|
|
64
|
+
defaultEdgeKind: 'association',
|
|
65
|
+
defaultStereotype: '«executes»',
|
|
66
|
+
description: 'Actor directly performs or executes Activity',
|
|
67
|
+
availableStereotypes: [
|
|
68
|
+
{
|
|
69
|
+
stereotype: '«executes»',
|
|
70
|
+
description: 'Actor performs this process step',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
stereotype: '«approves»',
|
|
74
|
+
description: 'Actor reviews or approves activity completion',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
'uc->uc': {
|
|
79
|
+
valid: true,
|
|
80
|
+
defaultEdgeKind: 'dependency',
|
|
81
|
+
defaultStereotype: '«includes»',
|
|
82
|
+
description: 'UseCase includes or extends sub-UseCase',
|
|
83
|
+
availableStereotypes: [
|
|
84
|
+
{
|
|
85
|
+
stereotype: '«includes»',
|
|
86
|
+
description: 'Mandatory sub-flow inclusion dependency',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
stereotype: '«extends»',
|
|
90
|
+
description: 'Optional conditional extension point',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
stereotype: '«dependsOn»',
|
|
94
|
+
description: 'Prerequisite functional dependency',
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
'uc->act': {
|
|
99
|
+
valid: true,
|
|
100
|
+
defaultEdgeKind: 'dependency',
|
|
101
|
+
defaultStereotype: '«includes»',
|
|
102
|
+
description: 'UseCase elaborates downflow process Activity',
|
|
103
|
+
availableStereotypes: [
|
|
104
|
+
{
|
|
105
|
+
stereotype: '«includes»',
|
|
106
|
+
description: 'Process activity required by UseCase',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
stereotype: '«triggers»',
|
|
110
|
+
description: 'UseCase execution triggers activity',
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
'act->act': {
|
|
115
|
+
valid: true,
|
|
116
|
+
defaultEdgeKind: 'association',
|
|
117
|
+
defaultStereotype: '«sequence»',
|
|
118
|
+
description: 'Activity transitions to next process step',
|
|
119
|
+
availableStereotypes: [
|
|
120
|
+
{
|
|
121
|
+
stereotype: '«sequence»',
|
|
122
|
+
description: 'Sequential process transition',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
stereotype: '«branch»',
|
|
126
|
+
description: 'Conditional decision branch',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
'cls->cls': {
|
|
131
|
+
valid: true,
|
|
132
|
+
defaultEdgeKind: 'association',
|
|
133
|
+
defaultStereotype: '«relatesTo»',
|
|
134
|
+
description: 'Domain structural relationship between Classes',
|
|
135
|
+
availableStereotypes: [
|
|
136
|
+
{
|
|
137
|
+
stereotype: '«relatesTo»',
|
|
138
|
+
defaultCardinality: '1..*',
|
|
139
|
+
description: 'General domain association',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
stereotype: '«generalization»',
|
|
143
|
+
description: 'Inheritance classification (subclass is-a superclass)',
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
stereotype: '«composition»',
|
|
147
|
+
defaultCardinality: '1',
|
|
148
|
+
description: 'Composite whole-part lifecycle binding',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
stereotype: '«aggregation»',
|
|
152
|
+
defaultCardinality: '0..*',
|
|
153
|
+
description: 'Shared aggregation relationship',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
'cls->obj': {
|
|
158
|
+
valid: true,
|
|
159
|
+
defaultEdgeKind: 'dependency',
|
|
160
|
+
defaultStereotype: '«instantiates»',
|
|
161
|
+
description: 'Class specifies runtime Object instance',
|
|
162
|
+
availableStereotypes: [
|
|
163
|
+
{
|
|
164
|
+
stereotype: '«instantiates»',
|
|
165
|
+
description: 'Class defines schema for runtime instance',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
'obj->obj': {
|
|
170
|
+
valid: true,
|
|
171
|
+
defaultEdgeKind: 'association',
|
|
172
|
+
defaultStereotype: '«link»',
|
|
173
|
+
description: 'Runtime communication link between Objects',
|
|
174
|
+
availableStereotypes: [
|
|
175
|
+
{
|
|
176
|
+
stereotype: '«link»',
|
|
177
|
+
description: 'Runtime object collaboration message link',
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Validates whether an edge connection between source and target archetypes is ontologically allowed.
|
|
185
|
+
*/
|
|
186
|
+
export function validateSemanticConnection(
|
|
187
|
+
sourceKind: AimOntologyKind | string,
|
|
188
|
+
targetKind: AimOntologyKind | string,
|
|
189
|
+
): boolean {
|
|
190
|
+
if (!sourceKind || !targetKind) return false;
|
|
191
|
+
const key = `${sourceKind}->${targetKind}`;
|
|
192
|
+
return SEMANTIC_RULES_MATRIX[key]?.valid ?? false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Determines the canonical default relationship edge kind for a connected pair.
|
|
197
|
+
*/
|
|
198
|
+
export function getSemanticEdgeKind(
|
|
199
|
+
sourceKind: AimOntologyKind | string,
|
|
200
|
+
targetKind: AimOntologyKind | string,
|
|
201
|
+
): AimEdgeKind {
|
|
202
|
+
const key = `${sourceKind}->${targetKind}`;
|
|
203
|
+
return SEMANTIC_RULES_MATRIX[key]?.defaultEdgeKind ?? 'association';
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Determines the canonical default stereotype annotation for a connected pair.
|
|
208
|
+
*/
|
|
209
|
+
export function getSemanticEdgeStereotype(
|
|
210
|
+
sourceKind: AimOntologyKind | string,
|
|
211
|
+
targetKind: AimOntologyKind | string,
|
|
212
|
+
): string {
|
|
213
|
+
const key = `${sourceKind}->${targetKind}`;
|
|
214
|
+
return SEMANTIC_RULES_MATRIX[key]?.defaultStereotype ?? '';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Returns available ontological stereotypes and their default cardinalities for a pair.
|
|
219
|
+
*/
|
|
220
|
+
export function getAvailableStereotypes(
|
|
221
|
+
sourceKind: AimOntologyKind | string,
|
|
222
|
+
targetKind: AimOntologyKind | string,
|
|
223
|
+
): readonly StereotypeOption[] {
|
|
224
|
+
const key = `${sourceKind}->${targetKind}`;
|
|
225
|
+
return SEMANTIC_RULES_MATRIX[key]?.availableStereotypes ?? [];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Returns a human-readable description explaining the ontological relationship.
|
|
230
|
+
*/
|
|
231
|
+
export function getSemanticRuleDescription(
|
|
232
|
+
sourceKind: AimOntologyKind | string,
|
|
233
|
+
targetKind: AimOntologyKind | string,
|
|
234
|
+
): string {
|
|
235
|
+
const key = `${sourceKind}->${targetKind}`;
|
|
236
|
+
return SEMANTIC_RULES_MATRIX[key]?.description ?? 'Invalid ontological connection';
|
|
237
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -16,7 +16,15 @@
|
|
|
16
16
|
* - 'obj' : Object / Instance (runtime instance card with underlined title)
|
|
17
17
|
* - 'per' : Person / Actor (Initiating or Defined role stick-figure/card)
|
|
18
18
|
*/
|
|
19
|
-
export type AimOntologyKind = '
|
|
19
|
+
export type AimOntologyKind = 'act' | 'uc' | 'cls' | 'obj' | 'per';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Routing strategy for diagram edges.
|
|
23
|
+
* - 'manhattan': Obstacle-avoiding 90° orthogonal routing with rounded corners (default).
|
|
24
|
+
* - 'normal': Direct straight line point-to-point connection.
|
|
25
|
+
* - 'smooth': Curved cubic bezier spline between ports.
|
|
26
|
+
*/
|
|
27
|
+
export type AimRoutingMode = 'manhattan' | 'normal' | 'smooth';
|
|
20
28
|
|
|
21
29
|
/**
|
|
22
30
|
* Ontological relationship classifications in AOAIM.
|
|
@@ -126,6 +134,9 @@ export interface RaidEdgeData {
|
|
|
126
134
|
/** Multiplicity / Cardinality at the target end (e.g., '0..1', '*'). */
|
|
127
135
|
readonly targetCardinality?: string;
|
|
128
136
|
|
|
137
|
+
/** Routing strategy for this edge ('manhattan', 'normal', 'smooth'). */
|
|
138
|
+
readonly routing?: AimRoutingMode;
|
|
139
|
+
|
|
129
140
|
/** User-editable or router-computed Manhattan bend points. */
|
|
130
141
|
readonly bendPoints: readonly SvgBendPoint[];
|
|
131
142
|
}
|
|
@@ -172,6 +183,7 @@ export const AimSvgContract = {
|
|
|
172
183
|
ATTR_TARGET: 'aim-target',
|
|
173
184
|
ATTR_SOURCE_PORT: 'aim-source-port',
|
|
174
185
|
ATTR_TARGET_PORT: 'aim-target-port',
|
|
186
|
+
ATTR_ROUTING: 'aim-routing',
|
|
175
187
|
ATTR_BENDS: 'aim-bends',
|
|
176
188
|
|
|
177
189
|
// Selectors for DOM queries
|