@principal-ai/principal-view-core 0.5.6
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/README.md +126 -0
- package/dist/ConfigurationLoader.d.ts +76 -0
- package/dist/ConfigurationLoader.d.ts.map +1 -0
- package/dist/ConfigurationLoader.js +144 -0
- package/dist/ConfigurationLoader.js.map +1 -0
- package/dist/ConfigurationValidator.d.ts +31 -0
- package/dist/ConfigurationValidator.d.ts.map +1 -0
- package/dist/ConfigurationValidator.js +242 -0
- package/dist/ConfigurationValidator.js.map +1 -0
- package/dist/EventProcessor.d.ts +49 -0
- package/dist/EventProcessor.d.ts.map +1 -0
- package/dist/EventProcessor.js +215 -0
- package/dist/EventProcessor.js.map +1 -0
- package/dist/EventRecorderService.d.ts +305 -0
- package/dist/EventRecorderService.d.ts.map +1 -0
- package/dist/EventRecorderService.js +463 -0
- package/dist/EventRecorderService.js.map +1 -0
- package/dist/LibraryLoader.d.ts +63 -0
- package/dist/LibraryLoader.d.ts.map +1 -0
- package/dist/LibraryLoader.js +188 -0
- package/dist/LibraryLoader.js.map +1 -0
- package/dist/PathBasedEventProcessor.d.ts +90 -0
- package/dist/PathBasedEventProcessor.d.ts.map +1 -0
- package/dist/PathBasedEventProcessor.js +239 -0
- package/dist/PathBasedEventProcessor.js.map +1 -0
- package/dist/SessionManager.d.ts +194 -0
- package/dist/SessionManager.d.ts.map +1 -0
- package/dist/SessionManager.js +299 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/ValidationEngine.d.ts +31 -0
- package/dist/ValidationEngine.d.ts.map +1 -0
- package/dist/ValidationEngine.js +158 -0
- package/dist/ValidationEngine.js.map +1 -0
- package/dist/helpers/GraphInstrumentationHelper.d.ts +93 -0
- package/dist/helpers/GraphInstrumentationHelper.d.ts.map +1 -0
- package/dist/helpers/GraphInstrumentationHelper.js +248 -0
- package/dist/helpers/GraphInstrumentationHelper.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/config.d.ts +57 -0
- package/dist/rules/config.d.ts.map +1 -0
- package/dist/rules/config.js +382 -0
- package/dist/rules/config.js.map +1 -0
- package/dist/rules/engine.d.ts +70 -0
- package/dist/rules/engine.d.ts.map +1 -0
- package/dist/rules/engine.js +252 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/implementations/connection-type-references.d.ts +7 -0
- package/dist/rules/implementations/connection-type-references.d.ts.map +1 -0
- package/dist/rules/implementations/connection-type-references.js +104 -0
- package/dist/rules/implementations/connection-type-references.js.map +1 -0
- package/dist/rules/implementations/dead-end-states.d.ts +17 -0
- package/dist/rules/implementations/dead-end-states.d.ts.map +1 -0
- package/dist/rules/implementations/dead-end-states.js +72 -0
- package/dist/rules/implementations/dead-end-states.js.map +1 -0
- package/dist/rules/implementations/index.d.ts +24 -0
- package/dist/rules/implementations/index.d.ts.map +1 -0
- package/dist/rules/implementations/index.js +62 -0
- package/dist/rules/implementations/index.js.map +1 -0
- package/dist/rules/implementations/library-node-type-match.d.ts +17 -0
- package/dist/rules/implementations/library-node-type-match.d.ts.map +1 -0
- package/dist/rules/implementations/library-node-type-match.js +123 -0
- package/dist/rules/implementations/library-node-type-match.js.map +1 -0
- package/dist/rules/implementations/minimum-node-sources.d.ts +22 -0
- package/dist/rules/implementations/minimum-node-sources.d.ts.map +1 -0
- package/dist/rules/implementations/minimum-node-sources.js +54 -0
- package/dist/rules/implementations/minimum-node-sources.js.map +1 -0
- package/dist/rules/implementations/no-unknown-fields.d.ts +7 -0
- package/dist/rules/implementations/no-unknown-fields.d.ts.map +1 -0
- package/dist/rules/implementations/no-unknown-fields.js +211 -0
- package/dist/rules/implementations/no-unknown-fields.js.map +1 -0
- package/dist/rules/implementations/orphaned-edge-types.d.ts +7 -0
- package/dist/rules/implementations/orphaned-edge-types.d.ts.map +1 -0
- package/dist/rules/implementations/orphaned-edge-types.js +47 -0
- package/dist/rules/implementations/orphaned-edge-types.js.map +1 -0
- package/dist/rules/implementations/orphaned-node-types.d.ts +7 -0
- package/dist/rules/implementations/orphaned-node-types.d.ts.map +1 -0
- package/dist/rules/implementations/orphaned-node-types.js +50 -0
- package/dist/rules/implementations/orphaned-node-types.js.map +1 -0
- package/dist/rules/implementations/required-metadata.d.ts +7 -0
- package/dist/rules/implementations/required-metadata.d.ts.map +1 -0
- package/dist/rules/implementations/required-metadata.js +57 -0
- package/dist/rules/implementations/required-metadata.js.map +1 -0
- package/dist/rules/implementations/state-transition-references.d.ts +7 -0
- package/dist/rules/implementations/state-transition-references.d.ts.map +1 -0
- package/dist/rules/implementations/state-transition-references.js +135 -0
- package/dist/rules/implementations/state-transition-references.js.map +1 -0
- package/dist/rules/implementations/unreachable-states.d.ts +7 -0
- package/dist/rules/implementations/unreachable-states.d.ts.map +1 -0
- package/dist/rules/implementations/unreachable-states.js +80 -0
- package/dist/rules/implementations/unreachable-states.js.map +1 -0
- package/dist/rules/implementations/valid-action-patterns.d.ts +17 -0
- package/dist/rules/implementations/valid-action-patterns.d.ts.map +1 -0
- package/dist/rules/implementations/valid-action-patterns.js +109 -0
- package/dist/rules/implementations/valid-action-patterns.js.map +1 -0
- package/dist/rules/implementations/valid-color-format.d.ts +7 -0
- package/dist/rules/implementations/valid-color-format.d.ts.map +1 -0
- package/dist/rules/implementations/valid-color-format.js +91 -0
- package/dist/rules/implementations/valid-color-format.js.map +1 -0
- package/dist/rules/implementations/valid-edge-types.d.ts +7 -0
- package/dist/rules/implementations/valid-edge-types.d.ts.map +1 -0
- package/dist/rules/implementations/valid-edge-types.js +244 -0
- package/dist/rules/implementations/valid-edge-types.js.map +1 -0
- package/dist/rules/implementations/valid-node-types.d.ts +7 -0
- package/dist/rules/implementations/valid-node-types.d.ts.map +1 -0
- package/dist/rules/implementations/valid-node-types.js +175 -0
- package/dist/rules/implementations/valid-node-types.js.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +45 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/types.d.ts +309 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +35 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/types/canvas.d.ts +409 -0
- package/dist/types/canvas.d.ts.map +1 -0
- package/dist/types/canvas.js +70 -0
- package/dist/types/canvas.js.map +1 -0
- package/dist/types/index.d.ts +311 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/library.d.ts +185 -0
- package/dist/types/library.d.ts.map +1 -0
- package/dist/types/library.js +15 -0
- package/dist/types/library.js.map +1 -0
- package/dist/types/path-based-config.d.ts +230 -0
- package/dist/types/path-based-config.d.ts.map +1 -0
- package/dist/types/path-based-config.js +9 -0
- package/dist/types/path-based-config.js.map +1 -0
- package/dist/utils/CanvasConverter.d.ts +118 -0
- package/dist/utils/CanvasConverter.d.ts.map +1 -0
- package/dist/utils/CanvasConverter.js +315 -0
- package/dist/utils/CanvasConverter.js.map +1 -0
- package/dist/utils/GraphConverter.d.ts +18 -0
- package/dist/utils/GraphConverter.d.ts.map +1 -0
- package/dist/utils/GraphConverter.js +61 -0
- package/dist/utils/GraphConverter.js.map +1 -0
- package/dist/utils/LibraryConverter.d.ts +113 -0
- package/dist/utils/LibraryConverter.d.ts.map +1 -0
- package/dist/utils/LibraryConverter.js +166 -0
- package/dist/utils/LibraryConverter.js.map +1 -0
- package/dist/utils/PathMatcher.d.ts +55 -0
- package/dist/utils/PathMatcher.d.ts.map +1 -0
- package/dist/utils/PathMatcher.js +172 -0
- package/dist/utils/PathMatcher.js.map +1 -0
- package/dist/utils/YamlParser.d.ts +36 -0
- package/dist/utils/YamlParser.d.ts.map +1 -0
- package/dist/utils/YamlParser.js +63 -0
- package/dist/utils/YamlParser.js.map +1 -0
- package/package.json +47 -0
- package/src/ConfigurationLoader.test.ts +490 -0
- package/src/ConfigurationLoader.ts +185 -0
- package/src/ConfigurationValidator.test.ts +200 -0
- package/src/ConfigurationValidator.ts +283 -0
- package/src/EventProcessor.test.ts +405 -0
- package/src/EventProcessor.ts +250 -0
- package/src/EventRecorderService.test.ts +541 -0
- package/src/EventRecorderService.ts +744 -0
- package/src/LibraryLoader.ts +215 -0
- package/src/PathBasedEventProcessor.test.ts +567 -0
- package/src/PathBasedEventProcessor.ts +332 -0
- package/src/SessionManager.test.ts +424 -0
- package/src/SessionManager.ts +470 -0
- package/src/ValidationEngine.test.ts +371 -0
- package/src/ValidationEngine.ts +196 -0
- package/src/helpers/GraphInstrumentationHelper.test.ts +340 -0
- package/src/helpers/GraphInstrumentationHelper.ts +326 -0
- package/src/index.ts +85 -0
- package/src/rules/config.test.ts +278 -0
- package/src/rules/config.ts +459 -0
- package/src/rules/engine.test.ts +332 -0
- package/src/rules/engine.ts +318 -0
- package/src/rules/implementations/connection-type-references.ts +117 -0
- package/src/rules/implementations/dead-end-states.ts +101 -0
- package/src/rules/implementations/index.ts +73 -0
- package/src/rules/implementations/library-node-type-match.ts +148 -0
- package/src/rules/implementations/minimum-node-sources.ts +82 -0
- package/src/rules/implementations/no-unknown-fields.ts +342 -0
- package/src/rules/implementations/orphaned-edge-types.ts +55 -0
- package/src/rules/implementations/orphaned-node-types.ts +58 -0
- package/src/rules/implementations/required-metadata.ts +64 -0
- package/src/rules/implementations/state-transition-references.ts +151 -0
- package/src/rules/implementations/unreachable-states.ts +94 -0
- package/src/rules/implementations/valid-action-patterns.ts +136 -0
- package/src/rules/implementations/valid-color-format.ts +140 -0
- package/src/rules/implementations/valid-edge-types.ts +258 -0
- package/src/rules/implementations/valid-node-types.ts +189 -0
- package/src/rules/index.ts +95 -0
- package/src/rules/types.ts +426 -0
- package/src/types/canvas.ts +496 -0
- package/src/types/index.ts +382 -0
- package/src/types/library.ts +233 -0
- package/src/types/path-based-config.ts +281 -0
- package/src/utils/CanvasConverter.ts +431 -0
- package/src/utils/GraphConverter.test.ts +195 -0
- package/src/utils/GraphConverter.ts +71 -0
- package/src/utils/LibraryConverter.ts +245 -0
- package/src/utils/PathMatcher.test.ts +148 -0
- package/src/utils/PathMatcher.ts +183 -0
- package/src/utils/YamlParser.ts +75 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path-based configuration extensions for Milestone 1 & 2
|
|
3
|
+
*
|
|
4
|
+
* These types extend the core GraphConfiguration to support:
|
|
5
|
+
* - Path-based log association (Milestone 1)
|
|
6
|
+
* - Action pattern refinement (Milestone 2)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Log levels (matches logger package)
|
|
11
|
+
*/
|
|
12
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extended node type definition with source path mapping
|
|
16
|
+
*/
|
|
17
|
+
export interface PathBasedNodeTypeDefinition {
|
|
18
|
+
/** Base node type properties (inherited from NodeTypeDefinition) */
|
|
19
|
+
shape: 'circle' | 'rectangle' | 'hexagon' | 'diamond' | 'custom';
|
|
20
|
+
icon?: string;
|
|
21
|
+
color?: string;
|
|
22
|
+
size?: { width: number; height: number };
|
|
23
|
+
dataSchema: {
|
|
24
|
+
[field: string]: {
|
|
25
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
26
|
+
required?: boolean;
|
|
27
|
+
displayInLabel?: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
states?: Record<
|
|
31
|
+
string,
|
|
32
|
+
{
|
|
33
|
+
color?: string;
|
|
34
|
+
icon?: string;
|
|
35
|
+
label?: string;
|
|
36
|
+
}
|
|
37
|
+
>;
|
|
38
|
+
layout?: {
|
|
39
|
+
layer?: number;
|
|
40
|
+
cluster?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Manual position for 'manual' layout mode */
|
|
44
|
+
position?: { x: number; y: number };
|
|
45
|
+
|
|
46
|
+
/** MILESTONE 1: Source path mapping */
|
|
47
|
+
sources?: string[]; // e.g., ["lib/lock-manager.ts", "lib/**/*.ts"]
|
|
48
|
+
|
|
49
|
+
/** MILESTONE 2: Optional action patterns for refinement */
|
|
50
|
+
actions?: ActionPattern[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Action pattern for extracting structured events from logs (Milestone 2)
|
|
55
|
+
*/
|
|
56
|
+
export interface ActionPattern {
|
|
57
|
+
/** Regex pattern to match log message (with named capture groups) */
|
|
58
|
+
pattern: string;
|
|
59
|
+
|
|
60
|
+
/** Event type to emit when pattern matches */
|
|
61
|
+
event: string;
|
|
62
|
+
|
|
63
|
+
/** Component state to transition to (optional) */
|
|
64
|
+
state?: string;
|
|
65
|
+
|
|
66
|
+
/** Metadata template - extracts data from capture groups */
|
|
67
|
+
metadata?: Record<string, string>; // e.g., { lockId: "$lockId" }
|
|
68
|
+
|
|
69
|
+
/** Whether this action should trigger edge animations */
|
|
70
|
+
triggerEdges?: string[]; // Edge IDs or patterns
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Extended edge definition with action-based activation (Milestone 2)
|
|
75
|
+
*/
|
|
76
|
+
export interface PathBasedEdgeTypeDefinition {
|
|
77
|
+
/** Base edge properties */
|
|
78
|
+
style: 'solid' | 'dashed' | 'dotted' | 'animated';
|
|
79
|
+
color?: string;
|
|
80
|
+
width?: number;
|
|
81
|
+
directed?: boolean;
|
|
82
|
+
animated?: boolean;
|
|
83
|
+
label?: {
|
|
84
|
+
field?: string;
|
|
85
|
+
position?: 'start' | 'middle' | 'end';
|
|
86
|
+
};
|
|
87
|
+
animation?: {
|
|
88
|
+
type: 'flow' | 'pulse' | 'particle' | 'glow';
|
|
89
|
+
duration?: number;
|
|
90
|
+
color?: string;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** MILESTONE 2: Edge activation triggers */
|
|
94
|
+
activatedBy?: EdgeActivationTrigger[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Configuration for activating edges based on component actions
|
|
99
|
+
*/
|
|
100
|
+
export interface EdgeActivationTrigger {
|
|
101
|
+
/** Action that triggers this edge animation */
|
|
102
|
+
action: string;
|
|
103
|
+
|
|
104
|
+
/** Animation type to play */
|
|
105
|
+
animation: 'flow' | 'particle' | 'pulse' | 'glow';
|
|
106
|
+
|
|
107
|
+
/** Animation direction */
|
|
108
|
+
direction?: 'forward' | 'backward' | 'bidirectional';
|
|
109
|
+
|
|
110
|
+
/** Animation duration in milliseconds */
|
|
111
|
+
duration?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Extended graph configuration with path-based support
|
|
116
|
+
*/
|
|
117
|
+
export interface PathBasedGraphConfiguration {
|
|
118
|
+
metadata: {
|
|
119
|
+
name: string;
|
|
120
|
+
version: string;
|
|
121
|
+
description?: string;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** Node types with source path mapping */
|
|
125
|
+
nodeTypes: Record<string, PathBasedNodeTypeDefinition>;
|
|
126
|
+
|
|
127
|
+
/** Edge types with action-based activation */
|
|
128
|
+
edgeTypes: Record<string, PathBasedEdgeTypeDefinition>;
|
|
129
|
+
|
|
130
|
+
/** Allowed connections between node types */
|
|
131
|
+
allowedConnections: Array<{
|
|
132
|
+
from: string;
|
|
133
|
+
to: string;
|
|
134
|
+
via: string;
|
|
135
|
+
constraints?: {
|
|
136
|
+
maxInstances?: number;
|
|
137
|
+
bidirectional?: boolean;
|
|
138
|
+
exclusive?: boolean;
|
|
139
|
+
};
|
|
140
|
+
}>;
|
|
141
|
+
|
|
142
|
+
/** Optional validation rules */
|
|
143
|
+
validation?: any; // Reuse from base types
|
|
144
|
+
|
|
145
|
+
/** Display preferences */
|
|
146
|
+
display?: any; // Reuse from base types
|
|
147
|
+
|
|
148
|
+
/** Path-based configuration options */
|
|
149
|
+
pathBasedConfig?: PathBasedConfigOptions;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Configuration options for path-based log association
|
|
154
|
+
*/
|
|
155
|
+
export interface PathBasedConfigOptions {
|
|
156
|
+
/** Project root for normalizing paths */
|
|
157
|
+
projectRoot?: string;
|
|
158
|
+
|
|
159
|
+
/** Whether to enable source capture (default: true) */
|
|
160
|
+
captureSource?: boolean;
|
|
161
|
+
|
|
162
|
+
/** Whether to enable action pattern matching (default: false in M1, true in M2) */
|
|
163
|
+
enableActionPatterns?: boolean;
|
|
164
|
+
|
|
165
|
+
/** Default log level for filtering (default: 'info') */
|
|
166
|
+
logLevel?: LogLevel;
|
|
167
|
+
|
|
168
|
+
/** Whether to ignore logs without source information (default: false) */
|
|
169
|
+
ignoreUnsourced?: boolean;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Component activity event (Milestone 1)
|
|
174
|
+
* Generated when a log is associated with a component by source path
|
|
175
|
+
*/
|
|
176
|
+
export interface ComponentActivityEvent {
|
|
177
|
+
type: 'component-activity';
|
|
178
|
+
|
|
179
|
+
/** Component ID (node type) */
|
|
180
|
+
componentId: string;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Instance identifier for multi-instance components.
|
|
184
|
+
* If provided, targets a specific node instance (e.g., "client-1").
|
|
185
|
+
* If undefined, targets the node type as a whole.
|
|
186
|
+
*/
|
|
187
|
+
instanceId?: string;
|
|
188
|
+
|
|
189
|
+
/** Timestamp of the log */
|
|
190
|
+
timestamp: number;
|
|
191
|
+
|
|
192
|
+
/** Log level */
|
|
193
|
+
level: LogLevel;
|
|
194
|
+
|
|
195
|
+
/** Log message */
|
|
196
|
+
message: string;
|
|
197
|
+
|
|
198
|
+
/** Source location */
|
|
199
|
+
source: {
|
|
200
|
+
file: string;
|
|
201
|
+
line?: number;
|
|
202
|
+
column?: number;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/** Additional log arguments */
|
|
206
|
+
args?: any[];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Component action event (Milestone 2)
|
|
211
|
+
* Generated when a log matches an action pattern
|
|
212
|
+
*/
|
|
213
|
+
export interface ComponentActionEvent {
|
|
214
|
+
type: 'component-action';
|
|
215
|
+
|
|
216
|
+
/** Component ID (node type) */
|
|
217
|
+
componentId: string;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Instance identifier for multi-instance components.
|
|
221
|
+
* If provided, targets a specific node instance (e.g., "client-1").
|
|
222
|
+
* If undefined, targets the node type as a whole.
|
|
223
|
+
*/
|
|
224
|
+
instanceId?: string;
|
|
225
|
+
|
|
226
|
+
/** Action type (from pattern) */
|
|
227
|
+
action: string;
|
|
228
|
+
|
|
229
|
+
/** New state (if specified in pattern) */
|
|
230
|
+
state?: string;
|
|
231
|
+
|
|
232
|
+
/** Timestamp of the log */
|
|
233
|
+
timestamp: number;
|
|
234
|
+
|
|
235
|
+
/** Extracted metadata from capture groups */
|
|
236
|
+
metadata?: Record<string, any>;
|
|
237
|
+
|
|
238
|
+
/** Source location */
|
|
239
|
+
source: {
|
|
240
|
+
file: string;
|
|
241
|
+
line?: number;
|
|
242
|
+
column?: number;
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Edge animation event (Milestone 2)
|
|
248
|
+
* Generated when a component action triggers edge activation
|
|
249
|
+
*/
|
|
250
|
+
export interface EdgeAnimationEvent {
|
|
251
|
+
type: 'edge-animation';
|
|
252
|
+
|
|
253
|
+
/** Edge ID to animate */
|
|
254
|
+
edgeId: string;
|
|
255
|
+
|
|
256
|
+
/** Animation type */
|
|
257
|
+
animation: 'flow' | 'particle' | 'pulse' | 'glow';
|
|
258
|
+
|
|
259
|
+
/** Animation direction */
|
|
260
|
+
direction?: 'forward' | 'backward' | 'bidirectional';
|
|
261
|
+
|
|
262
|
+
/** Animation duration */
|
|
263
|
+
duration: number;
|
|
264
|
+
|
|
265
|
+
/** Timestamp */
|
|
266
|
+
timestamp: number;
|
|
267
|
+
|
|
268
|
+
/** Source action that triggered this */
|
|
269
|
+
triggeredBy?: {
|
|
270
|
+
componentId: string;
|
|
271
|
+
action: string;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Union type of all path-based events
|
|
277
|
+
*/
|
|
278
|
+
export type PathBasedEvent =
|
|
279
|
+
| ComponentActivityEvent
|
|
280
|
+
| ComponentActionEvent
|
|
281
|
+
| EdgeAnimationEvent;
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas Converter
|
|
3
|
+
*
|
|
4
|
+
* Utilities for converting between Extended Canvas format and React Flow nodes/edges.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
ExtendedCanvas,
|
|
9
|
+
ExtendedCanvasNode,
|
|
10
|
+
ExtendedCanvasEdge,
|
|
11
|
+
PVEdgeTypeDefinition,
|
|
12
|
+
PVNodeShape,
|
|
13
|
+
PVEdgeStyle,
|
|
14
|
+
PVAnimationType,
|
|
15
|
+
} from '../types/canvas';
|
|
16
|
+
import { resolveCanvasColor } from '../types/canvas';
|
|
17
|
+
import type { NodeState, EdgeState } from '../types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* React Flow node format
|
|
21
|
+
*/
|
|
22
|
+
export interface ReactFlowNode {
|
|
23
|
+
id: string;
|
|
24
|
+
type: string;
|
|
25
|
+
position: { x: number; y: number };
|
|
26
|
+
data: {
|
|
27
|
+
label: string;
|
|
28
|
+
nodeType: string;
|
|
29
|
+
shape?: string;
|
|
30
|
+
icon?: string;
|
|
31
|
+
color?: string;
|
|
32
|
+
width?: number;
|
|
33
|
+
height?: number;
|
|
34
|
+
states?: Record<string, { color?: string; icon?: string; label?: string }>;
|
|
35
|
+
sources?: string[];
|
|
36
|
+
actions?: any[];
|
|
37
|
+
canvasType?: 'text' | 'file' | 'link' | 'group';
|
|
38
|
+
text?: string;
|
|
39
|
+
file?: string;
|
|
40
|
+
url?: string;
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
};
|
|
43
|
+
style?: {
|
|
44
|
+
width?: number;
|
|
45
|
+
height?: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* React Flow edge format
|
|
51
|
+
*/
|
|
52
|
+
export interface ReactFlowEdge {
|
|
53
|
+
id: string;
|
|
54
|
+
source: string;
|
|
55
|
+
target: string;
|
|
56
|
+
type?: string;
|
|
57
|
+
sourceHandle?: string;
|
|
58
|
+
targetHandle?: string;
|
|
59
|
+
label?: string;
|
|
60
|
+
data?: {
|
|
61
|
+
edgeType: string;
|
|
62
|
+
style?: string;
|
|
63
|
+
color?: string;
|
|
64
|
+
width?: number;
|
|
65
|
+
animation?: {
|
|
66
|
+
type: string;
|
|
67
|
+
duration?: number;
|
|
68
|
+
color?: string;
|
|
69
|
+
};
|
|
70
|
+
activatedBy?: any[];
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
};
|
|
73
|
+
style?: {
|
|
74
|
+
stroke?: string;
|
|
75
|
+
strokeWidth?: number;
|
|
76
|
+
strokeDasharray?: string;
|
|
77
|
+
};
|
|
78
|
+
animated?: boolean;
|
|
79
|
+
markerEnd?: {
|
|
80
|
+
type: string;
|
|
81
|
+
color?: string;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Convert canvas side to React Flow handle position
|
|
87
|
+
*/
|
|
88
|
+
function sideToHandle(side?: string): string | undefined {
|
|
89
|
+
if (!side) return undefined;
|
|
90
|
+
// React Flow uses 'top', 'right', 'bottom', 'left' - same as canvas
|
|
91
|
+
return side;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Convert edge style to stroke-dasharray
|
|
96
|
+
*/
|
|
97
|
+
function styleToStrokeDasharray(style?: string): string | undefined {
|
|
98
|
+
switch (style) {
|
|
99
|
+
case 'dashed':
|
|
100
|
+
return '5,5';
|
|
101
|
+
case 'dotted':
|
|
102
|
+
return '2,2';
|
|
103
|
+
default:
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Canvas Converter utility class
|
|
110
|
+
*/
|
|
111
|
+
export class CanvasConverter {
|
|
112
|
+
/**
|
|
113
|
+
* Convert Extended Canvas to React Flow nodes and edges
|
|
114
|
+
*/
|
|
115
|
+
static canvasToReactFlow(canvas: ExtendedCanvas): {
|
|
116
|
+
nodes: ReactFlowNode[];
|
|
117
|
+
edges: ReactFlowEdge[];
|
|
118
|
+
} {
|
|
119
|
+
const nodes: ReactFlowNode[] = [];
|
|
120
|
+
const edges: ReactFlowEdge[] = [];
|
|
121
|
+
|
|
122
|
+
// Convert nodes
|
|
123
|
+
if (canvas.nodes) {
|
|
124
|
+
for (const node of canvas.nodes) {
|
|
125
|
+
nodes.push(this.convertNode(node, canvas));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Convert edges
|
|
130
|
+
if (canvas.edges) {
|
|
131
|
+
for (const edge of canvas.edges) {
|
|
132
|
+
edges.push(this.convertEdge(edge, canvas));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return { nodes, edges };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Convert a single canvas node to React Flow node
|
|
141
|
+
*/
|
|
142
|
+
private static convertNode(node: ExtendedCanvasNode, canvas: ExtendedCanvas): ReactFlowNode {
|
|
143
|
+
const pv = node.pv;
|
|
144
|
+
const color = resolveCanvasColor(node.color);
|
|
145
|
+
|
|
146
|
+
// Build the data object based on canvas node type
|
|
147
|
+
const data: ReactFlowNode['data'] = {
|
|
148
|
+
label: this.getNodeLabel(node),
|
|
149
|
+
nodeType: pv?.nodeType || node.id,
|
|
150
|
+
canvasType: node.type,
|
|
151
|
+
shape: pv?.shape || 'rectangle',
|
|
152
|
+
icon: pv?.icon,
|
|
153
|
+
color: pv?.states?.idle?.color || color,
|
|
154
|
+
width: node.width,
|
|
155
|
+
height: node.height,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Add type-specific data
|
|
159
|
+
if (node.type === 'text') {
|
|
160
|
+
data.text = node.text;
|
|
161
|
+
} else if (node.type === 'file') {
|
|
162
|
+
data.file = node.file;
|
|
163
|
+
} else if (node.type === 'link') {
|
|
164
|
+
data.url = node.url;
|
|
165
|
+
} else if (node.type === 'group') {
|
|
166
|
+
data.label = node.label || data.label;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Add PV extensions if present
|
|
170
|
+
if (pv) {
|
|
171
|
+
data.states = pv.states;
|
|
172
|
+
data.sources = pv.sources;
|
|
173
|
+
data.actions = pv.actions;
|
|
174
|
+
if (pv.dataSchema) {
|
|
175
|
+
data.dataSchema = pv.dataSchema;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
id: node.id,
|
|
181
|
+
type: pv?.shape || 'default',
|
|
182
|
+
position: { x: node.x, y: node.y },
|
|
183
|
+
data,
|
|
184
|
+
style: {
|
|
185
|
+
width: node.width,
|
|
186
|
+
height: node.height,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get display label for a node
|
|
193
|
+
*/
|
|
194
|
+
private static getNodeLabel(node: ExtendedCanvasNode): string {
|
|
195
|
+
if (node.pv?.nodeType) {
|
|
196
|
+
return node.pv.nodeType;
|
|
197
|
+
}
|
|
198
|
+
switch (node.type) {
|
|
199
|
+
case 'text':
|
|
200
|
+
// Use first line of text as label
|
|
201
|
+
const firstLine = node.text.split('\n')[0];
|
|
202
|
+
return firstLine.replace(/^#+ /, '').substring(0, 50);
|
|
203
|
+
case 'file':
|
|
204
|
+
// Use filename as label
|
|
205
|
+
return node.file.split('/').pop() || node.file;
|
|
206
|
+
case 'link':
|
|
207
|
+
return node.url;
|
|
208
|
+
case 'group':
|
|
209
|
+
return node.label || 'Group';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Convert a single canvas edge to React Flow edge
|
|
215
|
+
*/
|
|
216
|
+
private static convertEdge(edge: ExtendedCanvasEdge, canvas: ExtendedCanvas): ReactFlowEdge {
|
|
217
|
+
const pv = edge.pv;
|
|
218
|
+
const edgeTypeDef = pv?.edgeType ? canvas.pv?.edgeTypes?.[pv.edgeType] : undefined;
|
|
219
|
+
const color = resolveCanvasColor(edge.color) || edgeTypeDef?.color;
|
|
220
|
+
|
|
221
|
+
const rfEdge: ReactFlowEdge = {
|
|
222
|
+
id: edge.id,
|
|
223
|
+
source: edge.fromNode,
|
|
224
|
+
target: edge.toNode,
|
|
225
|
+
sourceHandle: sideToHandle(edge.fromSide),
|
|
226
|
+
targetHandle: sideToHandle(edge.toSide),
|
|
227
|
+
label: edge.label,
|
|
228
|
+
data: {
|
|
229
|
+
edgeType: pv?.edgeType || 'default',
|
|
230
|
+
style: pv?.style || edgeTypeDef?.style || 'solid',
|
|
231
|
+
color,
|
|
232
|
+
width: pv?.width || edgeTypeDef?.width || 2,
|
|
233
|
+
animation: pv?.animation || edgeTypeDef?.animation,
|
|
234
|
+
activatedBy: pv?.activatedBy || edgeTypeDef?.activatedBy,
|
|
235
|
+
},
|
|
236
|
+
style: {
|
|
237
|
+
stroke: color,
|
|
238
|
+
strokeWidth: pv?.width || edgeTypeDef?.width || 2,
|
|
239
|
+
strokeDasharray: styleToStrokeDasharray(pv?.style || edgeTypeDef?.style),
|
|
240
|
+
},
|
|
241
|
+
animated: pv?.style === 'animated' || edgeTypeDef?.style === 'animated',
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Add marker based on canvas endpoint settings
|
|
245
|
+
if (edge.toEnd !== 'none') {
|
|
246
|
+
rfEdge.markerEnd = {
|
|
247
|
+
type: 'arrowclosed',
|
|
248
|
+
color,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return rfEdge;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Convert Extended Canvas to internal NodeState/EdgeState format
|
|
257
|
+
*/
|
|
258
|
+
static canvasToGraph(canvas: ExtendedCanvas): {
|
|
259
|
+
nodes: NodeState[];
|
|
260
|
+
edges: EdgeState[];
|
|
261
|
+
} {
|
|
262
|
+
const nodes: NodeState[] = [];
|
|
263
|
+
const edges: EdgeState[] = [];
|
|
264
|
+
const now = Date.now();
|
|
265
|
+
|
|
266
|
+
// Convert nodes
|
|
267
|
+
if (canvas.nodes) {
|
|
268
|
+
for (const node of canvas.nodes) {
|
|
269
|
+
const pv = node.pv;
|
|
270
|
+
nodes.push({
|
|
271
|
+
id: node.id,
|
|
272
|
+
type: pv?.nodeType || node.type,
|
|
273
|
+
data: {
|
|
274
|
+
label: this.getNodeLabel(node),
|
|
275
|
+
shape: pv?.shape || 'rectangle',
|
|
276
|
+
icon: pv?.icon,
|
|
277
|
+
// Color priority: pv.fill > node.color
|
|
278
|
+
color: pv?.fill || resolveCanvasColor(node.color),
|
|
279
|
+
// Stroke color for borders
|
|
280
|
+
stroke: pv?.stroke,
|
|
281
|
+
width: node.width,
|
|
282
|
+
height: node.height,
|
|
283
|
+
sources: pv?.sources || [],
|
|
284
|
+
actions: pv?.actions || [],
|
|
285
|
+
states: pv?.states,
|
|
286
|
+
canvasType: node.type,
|
|
287
|
+
...(node.type === 'text' ? { text: node.text } : {}),
|
|
288
|
+
...(node.type === 'file' ? { file: node.file } : {}),
|
|
289
|
+
...(node.type === 'link' ? { url: node.url } : {}),
|
|
290
|
+
},
|
|
291
|
+
position: { x: node.x, y: node.y },
|
|
292
|
+
// Don't set a default state - only show state labels when explicitly set via events
|
|
293
|
+
state: undefined,
|
|
294
|
+
createdAt: now,
|
|
295
|
+
updatedAt: now,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Convert edges
|
|
301
|
+
if (canvas.edges) {
|
|
302
|
+
for (const edge of canvas.edges) {
|
|
303
|
+
const pv = edge.pv;
|
|
304
|
+
const edgeTypeDef = pv?.edgeType ? canvas.pv?.edgeTypes?.[pv.edgeType] : undefined;
|
|
305
|
+
|
|
306
|
+
edges.push({
|
|
307
|
+
id: edge.id,
|
|
308
|
+
type: pv?.edgeType || 'default',
|
|
309
|
+
from: edge.fromNode,
|
|
310
|
+
to: edge.toNode,
|
|
311
|
+
data: {
|
|
312
|
+
label: edge.label,
|
|
313
|
+
style: pv?.style || edgeTypeDef?.style || 'solid',
|
|
314
|
+
color: resolveCanvasColor(edge.color) || edgeTypeDef?.color,
|
|
315
|
+
width: pv?.width || edgeTypeDef?.width,
|
|
316
|
+
animation: pv?.animation || edgeTypeDef?.animation,
|
|
317
|
+
activatedBy: pv?.activatedBy || edgeTypeDef?.activatedBy,
|
|
318
|
+
fromSide: edge.fromSide,
|
|
319
|
+
toSide: edge.toSide,
|
|
320
|
+
},
|
|
321
|
+
createdAt: now,
|
|
322
|
+
updatedAt: now,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return { nodes, edges };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Convert React Flow nodes/edges back to Extended Canvas format
|
|
332
|
+
*/
|
|
333
|
+
static reactFlowToCanvas(
|
|
334
|
+
nodes: ReactFlowNode[],
|
|
335
|
+
edges: ReactFlowEdge[],
|
|
336
|
+
metadata?: { name?: string; version?: string; description?: string }
|
|
337
|
+
): ExtendedCanvas {
|
|
338
|
+
const canvas: ExtendedCanvas = {
|
|
339
|
+
nodes: [],
|
|
340
|
+
edges: [],
|
|
341
|
+
pv: {
|
|
342
|
+
version: metadata?.version || '1.0.0',
|
|
343
|
+
name: metadata?.name || 'Untitled',
|
|
344
|
+
description: metadata?.description,
|
|
345
|
+
edgeTypes: {},
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Collect edge types
|
|
350
|
+
const edgeTypes = new Map<string, PVEdgeTypeDefinition>();
|
|
351
|
+
|
|
352
|
+
// Convert nodes
|
|
353
|
+
for (const node of nodes) {
|
|
354
|
+
const canvasNode: ExtendedCanvasNode = {
|
|
355
|
+
id: node.id,
|
|
356
|
+
type: node.data.canvasType || 'text',
|
|
357
|
+
x: node.position.x,
|
|
358
|
+
y: node.position.y,
|
|
359
|
+
width: node.style?.width || node.data.width || 150,
|
|
360
|
+
height: node.style?.height || node.data.height || 80,
|
|
361
|
+
text: node.data.text || node.data.label || '',
|
|
362
|
+
} as ExtendedCanvasNode;
|
|
363
|
+
|
|
364
|
+
// Add color if present
|
|
365
|
+
if (node.data.color) {
|
|
366
|
+
canvasNode.color = node.data.color;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Add PV extension if there's custom data
|
|
370
|
+
if (node.data.nodeType || node.data.shape || node.data.sources?.length) {
|
|
371
|
+
canvasNode.pv = {
|
|
372
|
+
nodeType: node.data.nodeType || node.id,
|
|
373
|
+
shape: node.data.shape as PVNodeShape | undefined,
|
|
374
|
+
icon: node.data.icon,
|
|
375
|
+
states: node.data.states,
|
|
376
|
+
sources: node.data.sources,
|
|
377
|
+
actions: node.data.actions,
|
|
378
|
+
dataSchema: node.data.dataSchema,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
canvas.nodes!.push(canvasNode);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Convert edges
|
|
386
|
+
for (const edge of edges) {
|
|
387
|
+
const canvasEdge: ExtendedCanvasEdge = {
|
|
388
|
+
id: edge.id,
|
|
389
|
+
fromNode: edge.source,
|
|
390
|
+
toNode: edge.target,
|
|
391
|
+
fromSide: edge.sourceHandle as any,
|
|
392
|
+
toSide: edge.targetHandle as any,
|
|
393
|
+
label: edge.label as string | undefined,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Add color
|
|
397
|
+
if (edge.style?.stroke) {
|
|
398
|
+
canvasEdge.color = edge.style.stroke;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Add PV extension
|
|
402
|
+
if (edge.data?.edgeType) {
|
|
403
|
+
canvasEdge.pv = {
|
|
404
|
+
edgeType: edge.data.edgeType,
|
|
405
|
+
style: edge.data.style as PVEdgeStyle | undefined,
|
|
406
|
+
width: edge.data.width,
|
|
407
|
+
animation: edge.data.animation as { type: PVAnimationType; duration?: number; color?: string } | undefined,
|
|
408
|
+
activatedBy: edge.data.activatedBy,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// Collect edge type definition
|
|
412
|
+
if (!edgeTypes.has(edge.data.edgeType)) {
|
|
413
|
+
edgeTypes.set(edge.data.edgeType, {
|
|
414
|
+
style: edge.data.style as PVEdgeStyle | undefined,
|
|
415
|
+
color: edge.data.color,
|
|
416
|
+
width: edge.data.width,
|
|
417
|
+
animation: edge.data.animation as { type: PVAnimationType; duration?: number; color?: string } | undefined,
|
|
418
|
+
activatedBy: edge.data.activatedBy,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
canvas.edges!.push(canvasEdge);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Add collected edge types to canvas
|
|
427
|
+
canvas.pv!.edgeTypes = Object.fromEntries(edgeTypes);
|
|
428
|
+
|
|
429
|
+
return canvas;
|
|
430
|
+
}
|
|
431
|
+
}
|