@aetherwing/fcp-drawio 0.2.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/LICENSE +21 -0
- package/README.md +119 -0
- package/dist/adapter.d.ts +38 -0
- package/dist/adapter.js +259 -0
- package/dist/adapter.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/elk-layout.d.ts +49 -0
- package/dist/layout/elk-layout.js +144 -0
- package/dist/layout/elk-layout.js.map +1 -0
- package/dist/lib/drawio-cli.d.ts +22 -0
- package/dist/lib/drawio-cli.js +88 -0
- package/dist/lib/drawio-cli.js.map +1 -0
- package/dist/lib/node-types.d.ts +22 -0
- package/dist/lib/node-types.js +174 -0
- package/dist/lib/node-types.js.map +1 -0
- package/dist/lib/stencils/aws.d.ts +2 -0
- package/dist/lib/stencils/aws.js +69 -0
- package/dist/lib/stencils/aws.js.map +1 -0
- package/dist/lib/stencils/azure.d.ts +2 -0
- package/dist/lib/stencils/azure.js +54 -0
- package/dist/lib/stencils/azure.js.map +1 -0
- package/dist/lib/stencils/cisco.d.ts +2 -0
- package/dist/lib/stencils/cisco.js +30 -0
- package/dist/lib/stencils/cisco.js.map +1 -0
- package/dist/lib/stencils/gcp.d.ts +2 -0
- package/dist/lib/stencils/gcp.js +38 -0
- package/dist/lib/stencils/gcp.js.map +1 -0
- package/dist/lib/stencils/ibm.d.ts +2 -0
- package/dist/lib/stencils/ibm.js +32 -0
- package/dist/lib/stencils/ibm.js.map +1 -0
- package/dist/lib/stencils/index.d.ts +10 -0
- package/dist/lib/stencils/index.js +33 -0
- package/dist/lib/stencils/index.js.map +1 -0
- package/dist/lib/stencils/k8s.d.ts +2 -0
- package/dist/lib/stencils/k8s.js +32 -0
- package/dist/lib/stencils/k8s.js.map +1 -0
- package/dist/lib/stencils/types.d.ts +14 -0
- package/dist/lib/stencils/types.js +2 -0
- package/dist/lib/stencils/types.js.map +1 -0
- package/dist/lib/themes.d.ts +8 -0
- package/dist/lib/themes.js +32 -0
- package/dist/lib/themes.js.map +1 -0
- package/dist/model/defaults.d.ts +3 -0
- package/dist/model/defaults.js +26 -0
- package/dist/model/defaults.js.map +1 -0
- package/dist/model/diagram-model.d.ts +110 -0
- package/dist/model/diagram-model.js +938 -0
- package/dist/model/diagram-model.js.map +1 -0
- package/dist/model/event-log.d.ts +30 -0
- package/dist/model/event-log.js +112 -0
- package/dist/model/event-log.js.map +1 -0
- package/dist/model/id.d.ts +9 -0
- package/dist/model/id.js +35 -0
- package/dist/model/id.js.map +1 -0
- package/dist/model/reference-registry.d.ts +33 -0
- package/dist/model/reference-registry.js +143 -0
- package/dist/model/reference-registry.js.map +1 -0
- package/dist/model/spatial.d.ts +20 -0
- package/dist/model/spatial.js +59 -0
- package/dist/model/spatial.js.map +1 -0
- package/dist/parser/parse-op.d.ts +18 -0
- package/dist/parser/parse-op.js +430 -0
- package/dist/parser/parse-op.js.map +1 -0
- package/dist/parser/resolve-ref.d.ts +27 -0
- package/dist/parser/resolve-ref.js +232 -0
- package/dist/parser/resolve-ref.js.map +1 -0
- package/dist/parser/tokenizer.d.ts +6 -0
- package/dist/parser/tokenizer.js +7 -0
- package/dist/parser/tokenizer.js.map +1 -0
- package/dist/serialization/connector-intelligence.d.ts +35 -0
- package/dist/serialization/connector-intelligence.js +336 -0
- package/dist/serialization/connector-intelligence.js.map +1 -0
- package/dist/serialization/deserialize.d.ts +6 -0
- package/dist/serialization/deserialize.js +511 -0
- package/dist/serialization/deserialize.js.map +1 -0
- package/dist/serialization/serialize.d.ts +15 -0
- package/dist/serialization/serialize.js +332 -0
- package/dist/serialization/serialize.js.map +1 -0
- package/dist/server/intent-layer.d.ts +48 -0
- package/dist/server/intent-layer.js +1322 -0
- package/dist/server/intent-layer.js.map +1 -0
- package/dist/server/mcp-server.d.ts +7 -0
- package/dist/server/mcp-server.js +26 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/dist/server/model-map.d.ts +8 -0
- package/dist/server/model-map.js +240 -0
- package/dist/server/model-map.js.map +1 -0
- package/dist/server/query-handler.d.ts +19 -0
- package/dist/server/query-handler.js +148 -0
- package/dist/server/query-handler.js.map +1 -0
- package/dist/server/response-formatter.d.ts +56 -0
- package/dist/server/response-formatter.js +351 -0
- package/dist/server/response-formatter.js.map +1 -0
- package/dist/server/session-handler.d.ts +6 -0
- package/dist/server/session-handler.js +127 -0
- package/dist/server/session-handler.js.map +1 -0
- package/dist/types/index.d.ts +238 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/verb-specs.d.ts +6 -0
- package/dist/verb-specs.js +144 -0
- package/dist/verb-specs.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Scott Meyer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# fcp-drawio
|
|
2
|
+
|
|
3
|
+
MCP server for creating and editing draw.io diagrams through intent-level commands.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
fcp-drawio lets LLMs build architecture diagrams, flowcharts, and system maps by describing what they want -- not how to draw it. The LLM sends high-level operations like `add svc AuthService theme:blue` and `connect AuthService -> UserDB`, and fcp-drawio renders them into fully styled draw.io XML with automatic layout via ELK. Built on the [FCP](https://github.com/aetherwing-io/fcp) framework.
|
|
8
|
+
|
|
9
|
+
## Quick Example
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
drawio([
|
|
13
|
+
'add svc AuthService theme:blue',
|
|
14
|
+
'add db UserDB theme:green near:AuthService dir:right',
|
|
15
|
+
'connect AuthService -> UserDB label:queries',
|
|
16
|
+
])
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Response:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
+svc AuthService @(200,200 140x60) blue
|
|
23
|
+
+db UserDB @(400,200 120x80) green
|
|
24
|
+
~AuthService->UserDB "queries" solid
|
|
25
|
+
digest: 3s 1e 0g
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This produces a draw.io diagram with a blue rounded-rectangle service node, a green database cylinder, and a labeled edge between them -- all positioned automatically.
|
|
29
|
+
|
|
30
|
+
### Available MCP Tools
|
|
31
|
+
|
|
32
|
+
| Tool | Purpose |
|
|
33
|
+
|------|---------|
|
|
34
|
+
| `drawio(ops)` | Batch mutations -- add shapes, connect, style, group, layout |
|
|
35
|
+
| `drawio_query(q)` | Inspect the diagram -- map, list, describe, connections, find |
|
|
36
|
+
| `drawio_session(action)` | Lifecycle -- new, open, save, checkpoint, undo, redo |
|
|
37
|
+
| `drawio_help()` | Full reference card |
|
|
38
|
+
|
|
39
|
+
### Component Library
|
|
40
|
+
|
|
41
|
+
| Type | Shape | Use For |
|
|
42
|
+
|------|-------|---------|
|
|
43
|
+
| `svc` | Rounded rect | Services, components |
|
|
44
|
+
| `db` | Cylinder | Databases, storage |
|
|
45
|
+
| `api` | Hexagon | APIs, gateways |
|
|
46
|
+
| `queue` | Parallelogram | Queues, streams |
|
|
47
|
+
| `cloud` | Cloud | External services |
|
|
48
|
+
| `actor` | Person | Users, personas |
|
|
49
|
+
| `doc` | Document | Files, reports |
|
|
50
|
+
| `box` | Rectangle | Generic |
|
|
51
|
+
| `decision` | Diamond | Decisions, conditions |
|
|
52
|
+
| `circle` | Ellipse | States, events |
|
|
53
|
+
| `process` | Double-bordered rect | Predefined processes |
|
|
54
|
+
| `triangle` | Triangle | Warnings, deltas |
|
|
55
|
+
|
|
56
|
+
### Themes
|
|
57
|
+
|
|
58
|
+
Apply color themes to any shape: `blue`, `green`, `red`, `orange`, `purple`, `yellow`, `gray`, `dark`.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Requires Node >= 22.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install @aetherwing/fcp-drawio
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### MCP Client Configuration
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"drawio": {
|
|
74
|
+
"command": "node",
|
|
75
|
+
"args": ["node_modules/@aetherwing/fcp-drawio/dist/index.js"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Architecture
|
|
82
|
+
|
|
83
|
+
4-layer architecture:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
MCP Server (Intent Layer)
|
|
87
|
+
src/server/ -- Parses op strings, resolves refs, dispatches
|
|
88
|
+
|
|
|
89
|
+
Semantic Model (Domain Brain)
|
|
90
|
+
src/model/ -- In-memory entity graph, event sourcing
|
|
91
|
+
|
|
|
92
|
+
Layout (ELK)
|
|
93
|
+
Auto-layout via elkjs -- flow:TB, flow:LR, near/dir positioning
|
|
94
|
+
|
|
|
95
|
+
Serialization (XML)
|
|
96
|
+
src/serialization/ -- Semantic model <-> mxGraphModel XML
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Supporting modules:
|
|
100
|
+
|
|
101
|
+
- `src/parser/` -- Operation string parser
|
|
102
|
+
- `src/lib/` -- Component library, themes, stencils, draw.io CLI integration
|
|
103
|
+
|
|
104
|
+
See [`docs/`](docs/) for design documents and example outputs.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install
|
|
110
|
+
npm run build # tsc
|
|
111
|
+
npm test # vitest, 465 tests
|
|
112
|
+
npm run test:watch
|
|
113
|
+
npm run dev # tsc --watch
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
|
119
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FcpDomainAdapter, OpResult, QueryResult } from "@aetherwing/fcp-core";
|
|
2
|
+
import { EventLog } from "@aetherwing/fcp-core";
|
|
3
|
+
import type { ParsedOp } from "@aetherwing/fcp-core";
|
|
4
|
+
import type { DiagramEvent } from "./types/index.js";
|
|
5
|
+
import { DiagramModel } from "./model/diagram-model.js";
|
|
6
|
+
import { IntentLayer } from "./server/intent-layer.js";
|
|
7
|
+
/**
|
|
8
|
+
* Bridge between the generic fcp-core ParsedOp (Record<string, string> params,
|
|
9
|
+
* positionals array) and drawio's domain-specific ParsedOp (Map<string, string>
|
|
10
|
+
* params, verb-specific fields like type, target, targets, arrows).
|
|
11
|
+
*
|
|
12
|
+
* The existing IntentLayer already has a full string-based dispatch pipeline
|
|
13
|
+
* (string -> local parseOp -> domain ParsedOp -> handler). Rather than
|
|
14
|
+
* rewriting the entire IntentLayer, this adapter delegates to it via the
|
|
15
|
+
* original string-based path while satisfying the FcpDomainAdapter interface.
|
|
16
|
+
*/
|
|
17
|
+
export declare class DrawioAdapter implements FcpDomainAdapter<DiagramModel, DiagramEvent> {
|
|
18
|
+
private intent;
|
|
19
|
+
constructor(options?: {
|
|
20
|
+
drawioCliPath?: string | null;
|
|
21
|
+
});
|
|
22
|
+
/** Access the intent layer (for direct interaction if needed). */
|
|
23
|
+
get intentLayer(): IntentLayer;
|
|
24
|
+
createEmpty(title: string, _params: Record<string, string>): DiagramModel;
|
|
25
|
+
serialize(model: DiagramModel): string;
|
|
26
|
+
deserialize(data: Buffer | string): DiagramModel;
|
|
27
|
+
rebuildIndices(model: DiagramModel): void;
|
|
28
|
+
getDigest(model: DiagramModel): string;
|
|
29
|
+
/**
|
|
30
|
+
* Dispatch an operation. We use the raw string from the ParsedOp to feed
|
|
31
|
+
* back through the existing IntentLayer pipeline, which has its own parser.
|
|
32
|
+
* This avoids rewriting the entire IntentLayer to accept generic ParsedOps.
|
|
33
|
+
*/
|
|
34
|
+
dispatchOp(op: ParsedOp, _model: DiagramModel, _log: EventLog<DiagramEvent>): Promise<OpResult>;
|
|
35
|
+
dispatchQuery(query: string, _model: DiagramModel): Promise<string | QueryResult>;
|
|
36
|
+
reverseEvent(event: DiagramEvent, model: DiagramModel): void;
|
|
37
|
+
replayEvent(event: DiagramEvent, model: DiagramModel): void;
|
|
38
|
+
}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { IntentLayer } from "./server/intent-layer.js";
|
|
2
|
+
import { serializeDiagram } from "./serialization/serialize.js";
|
|
3
|
+
import { deserializeDiagram } from "./serialization/deserialize.js";
|
|
4
|
+
/**
|
|
5
|
+
* Bridge between the generic fcp-core ParsedOp (Record<string, string> params,
|
|
6
|
+
* positionals array) and drawio's domain-specific ParsedOp (Map<string, string>
|
|
7
|
+
* params, verb-specific fields like type, target, targets, arrows).
|
|
8
|
+
*
|
|
9
|
+
* The existing IntentLayer already has a full string-based dispatch pipeline
|
|
10
|
+
* (string -> local parseOp -> domain ParsedOp -> handler). Rather than
|
|
11
|
+
* rewriting the entire IntentLayer, this adapter delegates to it via the
|
|
12
|
+
* original string-based path while satisfying the FcpDomainAdapter interface.
|
|
13
|
+
*/
|
|
14
|
+
export class DrawioAdapter {
|
|
15
|
+
intent;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.intent = new IntentLayer(options);
|
|
18
|
+
}
|
|
19
|
+
/** Access the intent layer (for direct interaction if needed). */
|
|
20
|
+
get intentLayer() {
|
|
21
|
+
return this.intent;
|
|
22
|
+
}
|
|
23
|
+
createEmpty(title, _params) {
|
|
24
|
+
// Use the intent layer's session handler to create the new diagram
|
|
25
|
+
// This ensures the QueryHandler's model reference stays consistent
|
|
26
|
+
this.intent.executeSession(`new "${title}"`);
|
|
27
|
+
return this.intent.model;
|
|
28
|
+
}
|
|
29
|
+
serialize(model) {
|
|
30
|
+
return serializeDiagram(model.diagram);
|
|
31
|
+
}
|
|
32
|
+
deserialize(data) {
|
|
33
|
+
const xml = typeof data === "string" ? data : data.toString("utf-8");
|
|
34
|
+
const diagram = deserializeDiagram(xml);
|
|
35
|
+
// Update the intent layer's model in-place to preserve QueryHandler reference
|
|
36
|
+
this.intent.model.diagram = diagram;
|
|
37
|
+
if (diagram.pages.length > 0) {
|
|
38
|
+
this.intent.model.diagram.activePage = diagram.pages[0].id;
|
|
39
|
+
}
|
|
40
|
+
this.intent.model.rebuildRegistry();
|
|
41
|
+
this.intent.restoreStencilPacks();
|
|
42
|
+
return this.intent.model;
|
|
43
|
+
}
|
|
44
|
+
rebuildIndices(model) {
|
|
45
|
+
model.rebuildRegistry();
|
|
46
|
+
}
|
|
47
|
+
getDigest(model) {
|
|
48
|
+
return model.getDigest();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Dispatch an operation. We use the raw string from the ParsedOp to feed
|
|
52
|
+
* back through the existing IntentLayer pipeline, which has its own parser.
|
|
53
|
+
* This avoids rewriting the entire IntentLayer to accept generic ParsedOps.
|
|
54
|
+
*/
|
|
55
|
+
async dispatchOp(op, _model, _log) {
|
|
56
|
+
return this.intent.executeSingleOp(op.raw);
|
|
57
|
+
}
|
|
58
|
+
async dispatchQuery(query, _model) {
|
|
59
|
+
const result = this.intent.executeQuery(query);
|
|
60
|
+
// Handle async results (e.g., snapshot rendering)
|
|
61
|
+
if (result instanceof Promise) {
|
|
62
|
+
const resolved = await result;
|
|
63
|
+
// Map the internal QueryResult to fcp-core's QueryResult
|
|
64
|
+
if (typeof resolved === "string")
|
|
65
|
+
return resolved;
|
|
66
|
+
const qr = resolved;
|
|
67
|
+
return qr;
|
|
68
|
+
}
|
|
69
|
+
if (typeof result === "string")
|
|
70
|
+
return result;
|
|
71
|
+
// Map the internal QueryResult to fcp-core's QueryResult
|
|
72
|
+
const qr = result;
|
|
73
|
+
return qr;
|
|
74
|
+
}
|
|
75
|
+
reverseEvent(event, model) {
|
|
76
|
+
reverseEventOnModel(event, model);
|
|
77
|
+
}
|
|
78
|
+
replayEvent(event, model) {
|
|
79
|
+
replayEventOnModel(event, model);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Reverse a single event on the model (undo).
|
|
84
|
+
* Extracted from DiagramModel.reverseEvent for use by the adapter.
|
|
85
|
+
*/
|
|
86
|
+
function reverseEventOnModel(event, model) {
|
|
87
|
+
const page = model.getActivePage();
|
|
88
|
+
switch (event.type) {
|
|
89
|
+
case "shape_created":
|
|
90
|
+
page.shapes.delete(event.shape.id);
|
|
91
|
+
break;
|
|
92
|
+
case "shape_deleted":
|
|
93
|
+
page.shapes.set(event.shape.id, { ...event.shape });
|
|
94
|
+
break;
|
|
95
|
+
case "shape_modified": {
|
|
96
|
+
const shape = page.shapes.get(event.id);
|
|
97
|
+
if (shape)
|
|
98
|
+
Object.assign(shape, event.before);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "edge_created":
|
|
102
|
+
page.edges.delete(event.edge.id);
|
|
103
|
+
break;
|
|
104
|
+
case "edge_deleted":
|
|
105
|
+
page.edges.set(event.edge.id, { ...event.edge });
|
|
106
|
+
break;
|
|
107
|
+
case "edge_modified": {
|
|
108
|
+
const edge = page.edges.get(event.id);
|
|
109
|
+
if (edge)
|
|
110
|
+
Object.assign(edge, event.before);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case "group_created":
|
|
114
|
+
page.groups.delete(event.group.id);
|
|
115
|
+
for (const id of event.group.memberIds) {
|
|
116
|
+
const shape = page.shapes.get(id);
|
|
117
|
+
if (shape)
|
|
118
|
+
shape.parentGroup = null;
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case "group_dissolved":
|
|
122
|
+
page.groups.set(event.group.id, {
|
|
123
|
+
...event.group,
|
|
124
|
+
memberIds: new Set(event.group.memberIds),
|
|
125
|
+
});
|
|
126
|
+
for (const id of event.group.memberIds) {
|
|
127
|
+
const shape = page.shapes.get(id);
|
|
128
|
+
if (shape)
|
|
129
|
+
shape.parentGroup = event.group.id;
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
case "page_added": {
|
|
133
|
+
const idx = model.diagram.pages.findIndex((p) => p.id === event.page.id);
|
|
134
|
+
if (idx !== -1)
|
|
135
|
+
model.diagram.pages.splice(idx, 1);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "page_removed":
|
|
139
|
+
model.diagram.pages.push(event.page);
|
|
140
|
+
break;
|
|
141
|
+
case "layer_created": {
|
|
142
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
143
|
+
if (p) {
|
|
144
|
+
const idx = p.layers.findIndex((l) => l.id === event.layer.id);
|
|
145
|
+
if (idx !== -1)
|
|
146
|
+
p.layers.splice(idx, 1);
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case "layer_modified": {
|
|
151
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
152
|
+
if (p) {
|
|
153
|
+
const layer = p.layers.find((l) => l.id === event.layerId);
|
|
154
|
+
if (layer)
|
|
155
|
+
Object.assign(layer, event.before);
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case "flow_direction_changed": {
|
|
160
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
161
|
+
if (p)
|
|
162
|
+
p.flowDirection = event.before;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case "title_changed":
|
|
166
|
+
model.diagram.title = event.before;
|
|
167
|
+
break;
|
|
168
|
+
case "checkpoint":
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Replay a single event on the model (redo).
|
|
174
|
+
* Extracted from DiagramModel.replayEvent for use by the adapter.
|
|
175
|
+
*/
|
|
176
|
+
function replayEventOnModel(event, model) {
|
|
177
|
+
const page = model.getActivePage();
|
|
178
|
+
switch (event.type) {
|
|
179
|
+
case "shape_created":
|
|
180
|
+
page.shapes.set(event.shape.id, { ...event.shape });
|
|
181
|
+
break;
|
|
182
|
+
case "shape_deleted":
|
|
183
|
+
page.shapes.delete(event.shape.id);
|
|
184
|
+
break;
|
|
185
|
+
case "shape_modified": {
|
|
186
|
+
const shape = page.shapes.get(event.id);
|
|
187
|
+
if (shape)
|
|
188
|
+
Object.assign(shape, event.after);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "edge_created":
|
|
192
|
+
page.edges.set(event.edge.id, { ...event.edge });
|
|
193
|
+
break;
|
|
194
|
+
case "edge_deleted":
|
|
195
|
+
page.edges.delete(event.edge.id);
|
|
196
|
+
break;
|
|
197
|
+
case "edge_modified": {
|
|
198
|
+
const edge = page.edges.get(event.id);
|
|
199
|
+
if (edge)
|
|
200
|
+
Object.assign(edge, event.after);
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case "group_created":
|
|
204
|
+
page.groups.set(event.group.id, {
|
|
205
|
+
...event.group,
|
|
206
|
+
memberIds: new Set(event.group.memberIds),
|
|
207
|
+
});
|
|
208
|
+
for (const id of event.group.memberIds) {
|
|
209
|
+
const shape = page.shapes.get(id);
|
|
210
|
+
if (shape)
|
|
211
|
+
shape.parentGroup = event.group.id;
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
case "group_dissolved":
|
|
215
|
+
page.groups.delete(event.group.id);
|
|
216
|
+
for (const id of event.group.memberIds) {
|
|
217
|
+
const shape = page.shapes.get(id);
|
|
218
|
+
if (shape)
|
|
219
|
+
shape.parentGroup = null;
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
case "page_added":
|
|
223
|
+
model.diagram.pages.push(event.page);
|
|
224
|
+
break;
|
|
225
|
+
case "page_removed": {
|
|
226
|
+
const idx = model.diagram.pages.findIndex((p) => p.id === event.page.id);
|
|
227
|
+
if (idx !== -1)
|
|
228
|
+
model.diagram.pages.splice(idx, 1);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case "layer_created": {
|
|
232
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
233
|
+
if (p)
|
|
234
|
+
p.layers.push({ ...event.layer });
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case "layer_modified": {
|
|
238
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
239
|
+
if (p) {
|
|
240
|
+
const layer = p.layers.find((l) => l.id === event.layerId);
|
|
241
|
+
if (layer)
|
|
242
|
+
Object.assign(layer, event.after);
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case "flow_direction_changed": {
|
|
247
|
+
const p = model.diagram.pages.find((pg) => pg.id === event.pageId);
|
|
248
|
+
if (p)
|
|
249
|
+
p.flowDirection = event.after;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "title_changed":
|
|
253
|
+
model.diagram.title = event.after;
|
|
254
|
+
break;
|
|
255
|
+
case "checkpoint":
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Page, Point } from "../types/index.js";
|
|
2
|
+
export interface LayoutOptions {
|
|
3
|
+
algorithm: "layered" | "force" | "tree";
|
|
4
|
+
direction: "TB" | "LR" | "BT" | "RL";
|
|
5
|
+
spacing?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface LayoutResult {
|
|
8
|
+
shapePositions: Map<string, {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
}>;
|
|
12
|
+
edgeWaypoints: Map<string, Point[]>;
|
|
13
|
+
}
|
|
14
|
+
interface ElkNode {
|
|
15
|
+
id: string;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
x?: number;
|
|
19
|
+
y?: number;
|
|
20
|
+
children?: ElkNode[];
|
|
21
|
+
layoutOptions?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
interface ElkEdge {
|
|
24
|
+
id: string;
|
|
25
|
+
sources: string[];
|
|
26
|
+
targets: string[];
|
|
27
|
+
sections?: ElkSection[];
|
|
28
|
+
}
|
|
29
|
+
interface ElkSection {
|
|
30
|
+
startPoint: Point;
|
|
31
|
+
endPoint: Point;
|
|
32
|
+
bendPoints?: Point[];
|
|
33
|
+
}
|
|
34
|
+
interface ElkGraph {
|
|
35
|
+
id: string;
|
|
36
|
+
layoutOptions: Record<string, string>;
|
|
37
|
+
children: ElkNode[];
|
|
38
|
+
edges: ElkEdge[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build an ELK graph from a Page, respecting group hierarchy.
|
|
42
|
+
* Groups become parent nodes with children arrays.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildElkGraph(page: Page, options: LayoutOptions): ElkGraph;
|
|
45
|
+
/**
|
|
46
|
+
* Run ELK layout on a page and return new positions/waypoints.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runElkLayout(page: Page, options: LayoutOptions): Promise<LayoutResult>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// elkjs CJS default export needs interop cast under Node16 module resolution
|
|
2
|
+
import _ELK from "elkjs/lib/elk.bundled.js";
|
|
3
|
+
const ELK = _ELK;
|
|
4
|
+
// ── Algorithm + direction mapping ────────────────────────────
|
|
5
|
+
const ALGORITHM_MAP = {
|
|
6
|
+
layered: "org.eclipse.elk.layered",
|
|
7
|
+
force: "org.eclipse.elk.force",
|
|
8
|
+
tree: "org.eclipse.elk.mrtree",
|
|
9
|
+
};
|
|
10
|
+
const DIRECTION_MAP = {
|
|
11
|
+
TB: "DOWN",
|
|
12
|
+
LR: "RIGHT",
|
|
13
|
+
BT: "UP",
|
|
14
|
+
RL: "LEFT",
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build an ELK graph from a Page, respecting group hierarchy.
|
|
18
|
+
* Groups become parent nodes with children arrays.
|
|
19
|
+
*/
|
|
20
|
+
export function buildElkGraph(page, options) {
|
|
21
|
+
const spacing = String(options.spacing ?? 60);
|
|
22
|
+
const layoutOptions = {
|
|
23
|
+
"elk.algorithm": ALGORITHM_MAP[options.algorithm],
|
|
24
|
+
"elk.direction": DIRECTION_MAP[options.direction],
|
|
25
|
+
"elk.edgeRouting": "ORTHOGONAL",
|
|
26
|
+
"elk.spacing.nodeNode": spacing,
|
|
27
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": spacing,
|
|
28
|
+
};
|
|
29
|
+
// Collect shapes by group
|
|
30
|
+
const groupChildren = new Map();
|
|
31
|
+
const ungroupedShapes = [];
|
|
32
|
+
for (const shape of page.shapes.values()) {
|
|
33
|
+
if (shape.parentGroup) {
|
|
34
|
+
if (!groupChildren.has(shape.parentGroup)) {
|
|
35
|
+
groupChildren.set(shape.parentGroup, []);
|
|
36
|
+
}
|
|
37
|
+
groupChildren.get(shape.parentGroup).push(shape);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
ungroupedShapes.push(shape);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const children = [];
|
|
44
|
+
// Add ungrouped shapes as top-level children
|
|
45
|
+
for (const shape of ungroupedShapes) {
|
|
46
|
+
children.push({
|
|
47
|
+
id: shape.id,
|
|
48
|
+
width: shape.bounds.width,
|
|
49
|
+
height: shape.bounds.height,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Add groups as hierarchical nodes with children
|
|
53
|
+
for (const [groupId, group] of page.groups) {
|
|
54
|
+
const members = groupChildren.get(groupId) ?? [];
|
|
55
|
+
const elkChildren = members.map((shape) => ({
|
|
56
|
+
id: shape.id,
|
|
57
|
+
width: shape.bounds.width,
|
|
58
|
+
height: shape.bounds.height,
|
|
59
|
+
}));
|
|
60
|
+
children.push({
|
|
61
|
+
id: groupId,
|
|
62
|
+
width: group.bounds.width,
|
|
63
|
+
height: group.bounds.height,
|
|
64
|
+
children: elkChildren,
|
|
65
|
+
layoutOptions: {
|
|
66
|
+
"elk.algorithm": ALGORITHM_MAP[options.algorithm],
|
|
67
|
+
"elk.direction": DIRECTION_MAP[options.direction],
|
|
68
|
+
"elk.spacing.nodeNode": spacing,
|
|
69
|
+
"elk.padding": "[top=50,left=40,bottom=35,right=40]",
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Build edges — ELK expects sources/targets to reference node IDs
|
|
74
|
+
const edges = [];
|
|
75
|
+
for (const edge of page.edges.values()) {
|
|
76
|
+
edges.push({
|
|
77
|
+
id: edge.id,
|
|
78
|
+
sources: [edge.sourceId],
|
|
79
|
+
targets: [edge.targetId],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
id: "root",
|
|
84
|
+
layoutOptions,
|
|
85
|
+
children,
|
|
86
|
+
edges,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// ── Layout execution ────────────────────────────────────────
|
|
90
|
+
/**
|
|
91
|
+
* Run ELK layout on a page and return new positions/waypoints.
|
|
92
|
+
*/
|
|
93
|
+
export async function runElkLayout(page, options) {
|
|
94
|
+
const elk = new ELK();
|
|
95
|
+
const graph = buildElkGraph(page, options);
|
|
96
|
+
const layouted = await elk.layout(graph);
|
|
97
|
+
return extractLayoutResult(layouted, page);
|
|
98
|
+
}
|
|
99
|
+
// ── Result extraction ───────────────────────────────────────
|
|
100
|
+
/**
|
|
101
|
+
* Extract shape positions and edge waypoints from an ELK layout result.
|
|
102
|
+
* Converts relative coords within groups to absolute coords.
|
|
103
|
+
*/
|
|
104
|
+
function extractLayoutResult(elkResult, page) {
|
|
105
|
+
const shapePositions = new Map();
|
|
106
|
+
const edgeWaypoints = new Map();
|
|
107
|
+
if (!elkResult.children)
|
|
108
|
+
return { shapePositions, edgeWaypoints };
|
|
109
|
+
for (const node of elkResult.children) {
|
|
110
|
+
const x = node.x ?? 0;
|
|
111
|
+
const y = node.y ?? 0;
|
|
112
|
+
// Check if this is a group node (has children) or a shape
|
|
113
|
+
if (node.children && node.children.length > 0) {
|
|
114
|
+
// This is a group — set group position and convert children to absolute
|
|
115
|
+
shapePositions.set(node.id, { x, y });
|
|
116
|
+
for (const child of node.children) {
|
|
117
|
+
const childX = (child.x ?? 0) + x;
|
|
118
|
+
const childY = (child.y ?? 0) + y;
|
|
119
|
+
shapePositions.set(child.id, { x: childX, y: childY });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// This is a top-level shape
|
|
124
|
+
shapePositions.set(node.id, { x, y });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Extract edge waypoints from sections
|
|
128
|
+
if (elkResult.edges) {
|
|
129
|
+
for (const edge of elkResult.edges) {
|
|
130
|
+
if (edge.sections && edge.sections.length > 0) {
|
|
131
|
+
const section = edge.sections[0];
|
|
132
|
+
const waypoints = [];
|
|
133
|
+
if (section.bendPoints) {
|
|
134
|
+
for (const bp of section.bendPoints) {
|
|
135
|
+
waypoints.push({ x: bp.x, y: bp.y });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
edgeWaypoints.set(edge.id, waypoints);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { shapePositions, edgeWaypoints };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=elk-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elk-layout.js","sourceRoot":"","sources":["../../src/layout/elk-layout.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,IAAI,MAAM,0BAA0B,CAAC;AAC5C,MAAM,GAAG,GAAG,IAAkE,CAAC;AAgB/E,gEAAgE;AAEhE,MAAM,aAAa,GAA+C;IAChE,OAAO,EAAE,yBAAyB;IAClC,KAAK,EAAE,uBAAuB;IAC9B,IAAI,EAAE,wBAAwB;CAC/B,CAAC;AAEF,MAAM,aAAa,GAA+C;IAChE,EAAE,EAAE,MAAM;IACV,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,MAAM;CACX,CAAC;AAkCF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAU,EACV,OAAsB;IAEtB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAE9C,MAAM,aAAa,GAA2B;QAC5C,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;QACjD,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;QACjD,iBAAiB,EAAE,YAAY;QAC/B,sBAAsB,EAAE,OAAO;QAC/B,2CAA2C,EAAE,OAAO;KACrD,CAAC;IAEF,0BAA0B;IAC1B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAmB,CAAC;IACjD,MAAM,eAAe,GAAY,EAAE,CAAC;IAEpC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QACzC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC1C,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC3C,CAAC;YACD,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,6CAA6C;IAC7C,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,iDAAiD;IACjD,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,WAAW,GAAc,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACrD,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;SAC5B,CAAC,CAAC,CAAC;QAEJ,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,OAAO;YACX,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;YACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;YAC3B,QAAQ,EAAE,WAAW;YACrB,aAAa,EAAE;gBACb,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;gBACjD,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC;gBACjD,sBAAsB,EAAE,OAAO;gBAC/B,aAAa,EAAE,qCAAqC;aACrD;SACF,CAAC,CAAC;IACL,CAAC;IAED,kEAAkE;IAClE,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;YACxB,OAAO,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,EAAE,EAAE,MAAM;QACV,aAAa;QACb,QAAQ;QACR,KAAK;KACN,CAAC;AACJ,CAAC;AAED,+DAA+D;AAE/D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAU,EACV,OAAsB;IAEtB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAY,CAAC,CAAC;IAEhD,OAAO,mBAAmB,CAAC,QAAe,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,+DAA+D;AAE/D;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,SAA2E,EAC3E,IAAU;IAEV,MAAM,cAAc,GAAG,IAAI,GAAG,EAAoC,CAAC;IACnE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEjD,IAAI,CAAC,SAAS,CAAC,QAAQ;QAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;IAElE,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAEtB,0DAA0D;QAC1D,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,wEAAwE;YACxE,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAEtC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBAClC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBAClC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,4BAA4B;YAC5B,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAkD,EAAE,CAAC;YAChF,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACjC,MAAM,SAAS,GAAY,EAAE,CAAC;gBAC9B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;oBACvB,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;wBACpC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;gBACD,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AAC3C,CAAC"}
|