@bpmnkit/ascii 0.0.12 → 0.0.14
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 +3 -0
- package/dist/edges.d.ts +18 -0
- package/dist/edges.js +127 -0
- package/dist/grid.js +2 -2
- package/dist/render.js +122 -10
- package/dist/shapes.d.ts +8 -2
- package/dist/shapes.js +13 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -91,6 +91,9 @@ interface RenderOptions {
|
|
|
91
91
|
| [`@bpmnkit/connector-gen`](https://www.npmjs.com/package/@bpmnkit/connector-gen) | Generate connector templates from OpenAPI specs |
|
|
92
92
|
| [`@bpmnkit/cli`](https://www.npmjs.com/package/@bpmnkit/cli) | Camunda 8 command-line interface (casen) |
|
|
93
93
|
| [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
|
|
94
|
+
| [`@bpmnkit/cli-sdk`](https://www.npmjs.com/package/@bpmnkit/cli-sdk) | Plugin authoring SDK for the casen CLI |
|
|
95
|
+
| [`@bpmnkit/create-casen-plugin`](https://www.npmjs.com/package/@bpmnkit/create-casen-plugin) | Scaffold a new casen CLI plugin in seconds |
|
|
96
|
+
| [`@bpmnkit/casen-report`](https://www.npmjs.com/package/@bpmnkit/casen-report) | HTML reports from Camunda 8 incident and SLA data |
|
|
94
97
|
|
|
95
98
|
## License
|
|
96
99
|
|
package/dist/edges.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import type { AsciiGrid } from "./grid.js";
|
|
2
|
+
/**
|
|
3
|
+
* Draw an edge using explicit source/target port sides.
|
|
4
|
+
*
|
|
5
|
+
* srcPort — which side the edge exits the source element:
|
|
6
|
+
* "right" → standard horizontal exit (srcCol = first col after right border, srcRow = midRow)
|
|
7
|
+
* "top" → exits the top of source (srcCol = midCol, srcRow = midRow)
|
|
8
|
+
* "bottom" → exits the bottom of source (srcCol = midCol, srcRow = midRow)
|
|
9
|
+
*
|
|
10
|
+
* dstPort — which side the edge enters the target element:
|
|
11
|
+
* "left" → standard horizontal entry (dstCol = left border col, dstRow = midRow)
|
|
12
|
+
* "top" → enters the top of target (dstCol = midCol, dstRow = midRow)
|
|
13
|
+
* "bottom" → enters the bottom of target (dstCol = midCol, dstRow = midRow)
|
|
14
|
+
*
|
|
15
|
+
* For top/bottom ports the element's middle row (midRow) is passed as srcRow/dstRow;
|
|
16
|
+
* this function offsets by ±2 to reach the actual visible exit/entry row (one row
|
|
17
|
+
* outside the 3-row element box).
|
|
18
|
+
*/
|
|
19
|
+
export declare function drawPortedEdge(grid: AsciiGrid, srcCol: number, srcRow: number, srcPort: "right" | "top" | "bottom", dstCol: number, dstRow: number, dstPort: "left" | "top" | "bottom", label?: string): void;
|
|
2
20
|
/**
|
|
3
21
|
* Draw an orthogonal sequence-flow edge from a source exit point to a target
|
|
4
22
|
* entry point, with an optional short label floated above the edge mid-point.
|
package/dist/edges.js
CHANGED
|
@@ -1,4 +1,131 @@
|
|
|
1
1
|
import { truncate } from "./util.js";
|
|
2
|
+
/**
|
|
3
|
+
* Draw an edge using explicit source/target port sides.
|
|
4
|
+
*
|
|
5
|
+
* srcPort — which side the edge exits the source element:
|
|
6
|
+
* "right" → standard horizontal exit (srcCol = first col after right border, srcRow = midRow)
|
|
7
|
+
* "top" → exits the top of source (srcCol = midCol, srcRow = midRow)
|
|
8
|
+
* "bottom" → exits the bottom of source (srcCol = midCol, srcRow = midRow)
|
|
9
|
+
*
|
|
10
|
+
* dstPort — which side the edge enters the target element:
|
|
11
|
+
* "left" → standard horizontal entry (dstCol = left border col, dstRow = midRow)
|
|
12
|
+
* "top" → enters the top of target (dstCol = midCol, dstRow = midRow)
|
|
13
|
+
* "bottom" → enters the bottom of target (dstCol = midCol, dstRow = midRow)
|
|
14
|
+
*
|
|
15
|
+
* For top/bottom ports the element's middle row (midRow) is passed as srcRow/dstRow;
|
|
16
|
+
* this function offsets by ±2 to reach the actual visible exit/entry row (one row
|
|
17
|
+
* outside the 3-row element box).
|
|
18
|
+
*/
|
|
19
|
+
export function drawPortedEdge(grid, srcCol, srcRow, srcPort, dstCol, dstRow, dstPort, label) {
|
|
20
|
+
if (srcPort === "right" && dstPort === "left") {
|
|
21
|
+
drawEdge(grid, srcCol, srcRow, dstCol, dstRow, label);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// top exit → left entry
|
|
25
|
+
if (srcPort === "top" && dstPort === "left") {
|
|
26
|
+
if (srcRow > dstRow) {
|
|
27
|
+
// Target is ABOVE: go up from gateway top to target row, corner, then right
|
|
28
|
+
grid.setLine(srcCol, dstRow, "┌");
|
|
29
|
+
for (let r = dstRow + 1; r < srcRow - 1; r++)
|
|
30
|
+
grid.setLine(srcCol, r, "│");
|
|
31
|
+
drawHorizontalSegment(grid, srcCol + 1, dstCol - 2, dstRow);
|
|
32
|
+
grid.set(dstCol - 1, dstRow, "►");
|
|
33
|
+
if (label) {
|
|
34
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
35
|
+
grid.write(mid, dstRow - 1, truncate(label, dstCol - srcCol));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Target is at same row or below: route ABOVE the diagram via routeRow=1,
|
|
40
|
+
// then descend to target row. Path: up↑ at srcCol → right→ at routeRow → down↓ at dstCol-1 → ►
|
|
41
|
+
const routeRow = 1;
|
|
42
|
+
grid.setLine(srcCol, routeRow, "└"); // ↑ meets →
|
|
43
|
+
for (let r = routeRow + 1; r < srcRow - 1; r++)
|
|
44
|
+
grid.setLine(srcCol, r, "│");
|
|
45
|
+
drawHorizontalSegment(grid, srcCol + 1, dstCol - 2, routeRow);
|
|
46
|
+
grid.setLine(dstCol - 1, routeRow, "┐"); // ← meets ↓
|
|
47
|
+
for (let r = routeRow + 1; r < dstRow; r++)
|
|
48
|
+
grid.setLine(dstCol - 1, r, "│");
|
|
49
|
+
grid.set(dstCol - 1, dstRow, "►");
|
|
50
|
+
if (label) {
|
|
51
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
52
|
+
grid.write(mid, routeRow - 1, truncate(label, dstCol - srcCol));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// bottom exit → left entry
|
|
58
|
+
if (srcPort === "bottom" && dstPort === "left") {
|
|
59
|
+
if (srcRow < dstRow) {
|
|
60
|
+
// Target is BELOW: go down from gateway bottom to target row, corner, then right
|
|
61
|
+
grid.setLine(srcCol, dstRow, "└");
|
|
62
|
+
for (let r = srcRow + 2; r < dstRow; r++)
|
|
63
|
+
grid.setLine(srcCol, r, "│");
|
|
64
|
+
drawHorizontalSegment(grid, srcCol + 1, dstCol - 2, dstRow);
|
|
65
|
+
grid.set(dstCol - 1, dstRow, "►");
|
|
66
|
+
if (label) {
|
|
67
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
68
|
+
grid.write(mid, dstRow - 1, truncate(label, dstCol - srcCol));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Target is at same row or above: route BELOW the diagram, then ascend to target row.
|
|
73
|
+
// Path: down↓ at srcCol → right→ at routeRow → up↑ at dstCol-1 → ►
|
|
74
|
+
const routeRow = grid.rows - 2;
|
|
75
|
+
grid.setLine(srcCol, routeRow, "┌"); // ↓ meets →
|
|
76
|
+
for (let r = srcRow + 2; r < routeRow; r++)
|
|
77
|
+
grid.setLine(srcCol, r, "│");
|
|
78
|
+
drawHorizontalSegment(grid, srcCol + 1, dstCol - 2, routeRow);
|
|
79
|
+
grid.setLine(dstCol - 1, routeRow, "┘"); // ← meets ↑
|
|
80
|
+
for (let r = dstRow + 1; r < routeRow; r++)
|
|
81
|
+
grid.setLine(dstCol - 1, r, "│");
|
|
82
|
+
grid.set(dstCol - 1, dstRow, "►");
|
|
83
|
+
if (label) {
|
|
84
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
85
|
+
grid.write(mid, routeRow + 1, truncate(label, dstCol - srcCol));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// right exit → top entry: horizontal right to target center-col, then vertical DOWN to target top
|
|
91
|
+
if (srcPort === "right" && dstPort === "top") {
|
|
92
|
+
if (srcRow >= dstRow) {
|
|
93
|
+
drawEdge(grid, srcCol, srcRow, dstCol, dstRow, label);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Corner at (dstCol, srcRow): connecting left (← from src) and down (↓ to dst top)
|
|
97
|
+
drawHorizontalSegment(grid, srcCol, dstCol - 1, srcRow);
|
|
98
|
+
grid.setLine(dstCol, srcRow, "┐");
|
|
99
|
+
for (let r = srcRow + 1; r < dstRow - 2; r++)
|
|
100
|
+
grid.setLine(dstCol, r, "│");
|
|
101
|
+
grid.set(dstCol, dstRow - 2, "▼");
|
|
102
|
+
if (label) {
|
|
103
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
104
|
+
grid.write(mid, srcRow - 1, truncate(label, dstCol - srcCol));
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// right exit → bottom entry: horizontal right to target center-col, then vertical UP to target bottom
|
|
109
|
+
if (srcPort === "right" && dstPort === "bottom") {
|
|
110
|
+
if (srcRow <= dstRow) {
|
|
111
|
+
drawEdge(grid, srcCol, srcRow, dstCol, dstRow, label);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Corner at (dstCol, srcRow): connecting left (← from src) and up (↑ to dst bottom)
|
|
115
|
+
drawHorizontalSegment(grid, srcCol, dstCol - 1, srcRow);
|
|
116
|
+
grid.setLine(dstCol, srcRow, "┘");
|
|
117
|
+
for (let r = dstRow + 3; r < srcRow; r++)
|
|
118
|
+
grid.setLine(dstCol, r, "│");
|
|
119
|
+
grid.set(dstCol, dstRow + 2, "▲");
|
|
120
|
+
if (label) {
|
|
121
|
+
const mid = Math.floor((srcCol + dstCol) / 2) - Math.floor(label.length / 2);
|
|
122
|
+
grid.write(mid, srcRow - 1, truncate(label, dstCol - srcCol));
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Fallback for any other combination
|
|
127
|
+
drawEdge(grid, srcCol, srcRow, dstCol, dstRow, label);
|
|
128
|
+
}
|
|
2
129
|
/**
|
|
3
130
|
* Draw an orthogonal sequence-flow edge from a source exit point to a target
|
|
4
131
|
* entry point, with an optional short label floated above the edge mid-point.
|
package/dist/grid.js
CHANGED
|
@@ -75,9 +75,9 @@ export function mergeBoxChars(existing, next) {
|
|
|
75
75
|
if (existing === " " || existing === next)
|
|
76
76
|
return next;
|
|
77
77
|
// Arrows always win
|
|
78
|
-
if (next === "►" || next === "▼")
|
|
78
|
+
if (next === "►" || next === "▼" || next === "▲")
|
|
79
79
|
return next;
|
|
80
|
-
if (existing === "►" || existing === "▼")
|
|
80
|
+
if (existing === "►" || existing === "▼" || existing === "▲")
|
|
81
81
|
return existing;
|
|
82
82
|
const eDirs = CHAR_DIRS[existing];
|
|
83
83
|
const nDirs = CHAR_DIRS[next];
|
package/dist/render.js
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
import { Bpmn, layoutFlowNodes } from "@bpmnkit/core";
|
|
2
|
-
import {
|
|
1
|
+
import { Bpmn, GRID_CELL_HEIGHT, layoutFlowNodes } from "@bpmnkit/core";
|
|
2
|
+
import { drawPortedEdge } from "./edges.js";
|
|
3
3
|
import { AsciiGrid } from "./grid.js";
|
|
4
|
-
import { CELL_H, CELL_W, drawElement, entryCol, exitCol,
|
|
4
|
+
import { CELL_H, CELL_W, drawElement, entryCol, exitCol, midCol } from "./shapes.js";
|
|
5
|
+
/**
|
|
6
|
+
* Convert a node's pixel bounds to its ASCII mid-row (the middle of its 3-row box).
|
|
7
|
+
*
|
|
8
|
+
* The layout engine centers each element vertically within a GRID_CELL_HEIGHT-pixel
|
|
9
|
+
* tall cell. By recovering the cell's y-offset we get a stable ascii row index
|
|
10
|
+
* regardless of element type, and the centering applied by `centerLayersVertically`
|
|
11
|
+
* is preserved (e.g. a join node after 3 parallel branches appears in the middle).
|
|
12
|
+
*/
|
|
13
|
+
function nodeMidRow(node) {
|
|
14
|
+
// Recover the cell's top y (element is centred inside its cell)
|
|
15
|
+
const cellY = node.bounds.y + node.bounds.height / 2 - GRID_CELL_HEIGHT / 2;
|
|
16
|
+
// Scale from pixel rows to ASCII rows (CELL_H ascii rows per GRID_CELL_HEIGHT pixels)
|
|
17
|
+
const asciiCellRow = Math.round((cellY / GRID_CELL_HEIGHT) * CELL_H);
|
|
18
|
+
// midRow = cell top + vertical padding + 1 (same formula as the old elemRow+1)
|
|
19
|
+
return asciiCellRow + Math.floor((CELL_H - 3) / 2) + 1;
|
|
20
|
+
}
|
|
21
|
+
const GATEWAY_TYPES = new Set([
|
|
22
|
+
"exclusiveGateway",
|
|
23
|
+
"parallelGateway",
|
|
24
|
+
"inclusiveGateway",
|
|
25
|
+
"eventBasedGateway",
|
|
26
|
+
"complexGateway",
|
|
27
|
+
]);
|
|
5
28
|
/**
|
|
6
29
|
* Render a BPMN XML string as a Unicode box-drawing ASCII diagram.
|
|
7
30
|
*
|
|
@@ -15,33 +38,36 @@ export function renderBpmnAscii(xml, options) {
|
|
|
15
38
|
if (!process)
|
|
16
39
|
return "(empty)";
|
|
17
40
|
// Use layoutFlowNodes directly to skip the overlap assertion — the ASCII renderer
|
|
18
|
-
//
|
|
41
|
+
// re-scales pixel coords to character rows so pixel-level overlaps are harmless.
|
|
19
42
|
const layout = layoutFlowNodes(process.flowElements, process.sequenceFlows);
|
|
20
43
|
const { nodes, edges } = layout;
|
|
21
44
|
if (nodes.length === 0)
|
|
22
45
|
return "(empty)";
|
|
23
|
-
// Compute grid dimensions from the layout's layer
|
|
46
|
+
// Compute grid dimensions from the layout's layer extents and pixel bounds
|
|
24
47
|
const maxLayer = Math.max(...nodes.map((n) => n.layer));
|
|
25
|
-
const
|
|
26
|
-
// +2 padding on each axis, +1 because layers/positions are 0-indexed
|
|
48
|
+
const maxMidRow = Math.max(...nodes.map(nodeMidRow));
|
|
27
49
|
const gridCols = (maxLayer + 1) * CELL_W + 4;
|
|
28
|
-
|
|
50
|
+
// Element bottom is at maxMidRow+1; leave CELL_H rows of padding below.
|
|
51
|
+
const gridRows = maxMidRow + CELL_H + 1;
|
|
29
52
|
const grid = new AsciiGrid(gridCols, gridRows);
|
|
30
53
|
// Build an id → node map for O(1) edge-endpoint look-up
|
|
31
54
|
const nodeById = new Map();
|
|
32
55
|
for (const node of nodes)
|
|
33
56
|
nodeById.set(node.id, node);
|
|
57
|
+
// Pre-compute port assignments for all edges
|
|
58
|
+
const ports = computeEdgePorts(edges, nodeById);
|
|
34
59
|
// Draw edges first so that shapes render on top of any edge overlap
|
|
35
60
|
for (const edge of edges) {
|
|
36
61
|
const src = nodeById.get(edge.sourceRef);
|
|
37
62
|
const dst = nodeById.get(edge.targetRef);
|
|
38
63
|
if (!src || !dst)
|
|
39
64
|
continue;
|
|
40
|
-
|
|
65
|
+
const { srcPort, dstPort } = ports.get(edge.id) ?? { srcPort: "right", dstPort: "left" };
|
|
66
|
+
drawPortedEdge(grid, srcPort === "right" ? exitCol(src.type, src.layer) : midCol(src.type, src.layer), nodeMidRow(src), srcPort, dstPort === "left" ? entryCol(dst.type, dst.layer) : midCol(dst.type, dst.layer), nodeMidRow(dst), dstPort, edge.label);
|
|
41
67
|
}
|
|
42
68
|
// Draw element boxes on top
|
|
43
69
|
for (const node of nodes) {
|
|
44
|
-
drawElement(grid, node.type, node.layer, node
|
|
70
|
+
drawElement(grid, node.type, node.layer, nodeMidRow(node) - 1, node.label);
|
|
45
71
|
}
|
|
46
72
|
const diagram = grid.toString();
|
|
47
73
|
// Optional title header
|
|
@@ -59,4 +85,90 @@ function resolveTitle(options, processName) {
|
|
|
59
85
|
return options.title;
|
|
60
86
|
return processName ?? undefined;
|
|
61
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Assign source and target ports for every edge.
|
|
90
|
+
*
|
|
91
|
+
* Source ports for gateway outgoing edges:
|
|
92
|
+
* N=1 → right
|
|
93
|
+
* N=2 → top, bottom
|
|
94
|
+
* N=3 → top, right (middle by target row), bottom
|
|
95
|
+
* N=4 → top, top, bottom, bottom
|
|
96
|
+
* N=5 → top, top, right, bottom, bottom …and so on.
|
|
97
|
+
*
|
|
98
|
+
* Target ports are derived from the source port and relative positions:
|
|
99
|
+
* srcPort=top/bottom → dstPort=left (edge routes vertical then horizontal)
|
|
100
|
+
* srcPort=right, dst is gateway:
|
|
101
|
+
* source above dst → dstPort=top
|
|
102
|
+
* source below dst → dstPort=bottom
|
|
103
|
+
* same row → dstPort=left
|
|
104
|
+
* all other targets → dstPort=left
|
|
105
|
+
*/
|
|
106
|
+
function computeEdgePorts(edges, nodeById) {
|
|
107
|
+
// ── Step 1: assign source ports ──────────────────────────────────────────
|
|
108
|
+
const srcPorts = new Map();
|
|
109
|
+
// Collect forward gateway edges grouped by source
|
|
110
|
+
const bySource = new Map();
|
|
111
|
+
for (const edge of edges) {
|
|
112
|
+
const src = nodeById.get(edge.sourceRef);
|
|
113
|
+
const dst = nodeById.get(edge.targetRef);
|
|
114
|
+
// Back-edges (dst layer ≤ src layer) and non-gateway sources always exit right
|
|
115
|
+
if (!src || !dst || !GATEWAY_TYPES.has(src.type) || dst.layer <= src.layer) {
|
|
116
|
+
srcPorts.set(edge.id, "right");
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const arr = bySource.get(edge.sourceRef) ?? [];
|
|
120
|
+
arr.push(edge);
|
|
121
|
+
bySource.set(edge.sourceRef, arr);
|
|
122
|
+
}
|
|
123
|
+
for (const [, outgoing] of bySource) {
|
|
124
|
+
const n = outgoing.length;
|
|
125
|
+
if (n === 1) {
|
|
126
|
+
// biome-ignore lint/style/noNonNullAssertion: length=1 guarantees element
|
|
127
|
+
srcPorts.set(outgoing[0].id, "right");
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Sort outgoing edges by their target's row position (ascending = topmost first)
|
|
131
|
+
const sorted = [...outgoing].sort((a, b) => {
|
|
132
|
+
const pa = nodeById.get(a.targetRef)?.position ?? 0;
|
|
133
|
+
const pb = nodeById.get(b.targetRef)?.position ?? 0;
|
|
134
|
+
return pa - pb;
|
|
135
|
+
});
|
|
136
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
137
|
+
// biome-ignore lint/style/noNonNullAssertion: loop bounds guarantee element
|
|
138
|
+
const edge = sorted[i];
|
|
139
|
+
let port;
|
|
140
|
+
if (n % 2 === 1) {
|
|
141
|
+
// Odd: middle index → right, above → top, below → bottom
|
|
142
|
+
const mid = Math.floor(n / 2);
|
|
143
|
+
port = i < mid ? "top" : i === mid ? "right" : "bottom";
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Even: upper half → top, lower half → bottom (no right port)
|
|
147
|
+
port = i < n / 2 ? "top" : "bottom";
|
|
148
|
+
}
|
|
149
|
+
srcPorts.set(edge.id, port);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// ── Step 2: assign target ports ──────────────────────────────────────────
|
|
153
|
+
const result = new Map();
|
|
154
|
+
for (const edge of edges) {
|
|
155
|
+
const srcPort = srcPorts.get(edge.id) ?? "right";
|
|
156
|
+
let dstPort = "left";
|
|
157
|
+
// Top/bottom source ports route vertical-then-horizontal → always left entry.
|
|
158
|
+
// Right source port into a gateway: entry side depends on relative row.
|
|
159
|
+
if (srcPort === "right") {
|
|
160
|
+
const src = nodeById.get(edge.sourceRef);
|
|
161
|
+
const dst = nodeById.get(edge.targetRef);
|
|
162
|
+
if (src && dst && GATEWAY_TYPES.has(dst.type)) {
|
|
163
|
+
if (src.position < dst.position)
|
|
164
|
+
dstPort = "top";
|
|
165
|
+
else if (src.position > dst.position)
|
|
166
|
+
dstPort = "bottom";
|
|
167
|
+
// else same row → left (default)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
result.set(edge.id, { srcPort, dstPort });
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
62
174
|
//# sourceMappingURL=render.js.map
|
package/dist/shapes.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare const CELL_H = 8;
|
|
|
20
20
|
export declare function elemCol(type: string, layer: number): number;
|
|
21
21
|
/** Top-left row of a task or event element within its cell (3 rows tall). */
|
|
22
22
|
export declare function elemRow(position: number): number;
|
|
23
|
+
/** Column of the horizontal center of an element (for top/bottom connections). */
|
|
24
|
+
export declare function midCol(type: string, layer: number): number;
|
|
23
25
|
/**
|
|
24
26
|
* Column of the right exit connection point (first column AFTER the element's
|
|
25
27
|
* right border — where an outgoing edge begins).
|
|
@@ -32,6 +34,10 @@ export declare function exitCol(type: string, layer: number): number;
|
|
|
32
34
|
export declare function entryCol(type: string, layer: number): number;
|
|
33
35
|
/** Row of the horizontal mid-point (used as the connection row for edges). */
|
|
34
36
|
export declare function midRow(position: number): number;
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Draw any BPMN element onto the grid.
|
|
39
|
+
*
|
|
40
|
+
* @param row - The top row of the 3-row element box (pre-computed by the caller).
|
|
41
|
+
*/
|
|
42
|
+
export declare function drawElement(grid: AsciiGrid, type: string, layer: number, row: number, label: string | undefined): void;
|
|
37
43
|
//# sourceMappingURL=shapes.d.ts.map
|
package/dist/shapes.js
CHANGED
|
@@ -118,6 +118,10 @@ export function elemRow(position) {
|
|
|
118
118
|
// Centre the 3-row element vertically within the cell
|
|
119
119
|
return position * CELL_H + Math.floor((CELL_H - 3) / 2);
|
|
120
120
|
}
|
|
121
|
+
/** Column of the horizontal center of an element (for top/bottom connections). */
|
|
122
|
+
export function midCol(type, layer) {
|
|
123
|
+
return elemCol(type, layer) + Math.floor(elemW(type) / 2);
|
|
124
|
+
}
|
|
121
125
|
/**
|
|
122
126
|
* Column of the right exit connection point (first column AFTER the element's
|
|
123
127
|
* right border — where an outgoing edge begins).
|
|
@@ -137,18 +141,22 @@ export function midRow(position) {
|
|
|
137
141
|
return elemRow(position) + 1; // middle of the 3-row element
|
|
138
142
|
}
|
|
139
143
|
// ── Drawing ─────────────────────────────────────────────────────────────────
|
|
140
|
-
/**
|
|
141
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Draw any BPMN element onto the grid.
|
|
146
|
+
*
|
|
147
|
+
* @param row - The top row of the 3-row element box (pre-computed by the caller).
|
|
148
|
+
*/
|
|
149
|
+
export function drawElement(grid, type, layer, row, label) {
|
|
142
150
|
const col = elemCol(type, layer);
|
|
143
151
|
const name = label ?? "";
|
|
144
152
|
if (isTaskLike(type)) {
|
|
145
|
-
drawTaskBox(grid, col,
|
|
153
|
+
drawTaskBox(grid, col, row, name, type);
|
|
146
154
|
}
|
|
147
155
|
else if (isGateway(type)) {
|
|
148
|
-
drawGatewayBox(grid, col,
|
|
156
|
+
drawGatewayBox(grid, col, row, name, elementMarker(type));
|
|
149
157
|
}
|
|
150
158
|
else {
|
|
151
|
-
drawCompactBox(grid, col,
|
|
159
|
+
drawCompactBox(grid, col, row, name, elementMarker(type));
|
|
152
160
|
}
|
|
153
161
|
}
|
|
154
162
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bpmnkit/ascii",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dist/**/*.d.ts"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@bpmnkit/core": "0.0.
|
|
20
|
+
"@bpmnkit/core": "0.0.14"
|
|
21
21
|
},
|
|
22
22
|
"description": "Render BPMN diagrams as Unicode box-drawing ASCII art — perfect for terminals and docs",
|
|
23
23
|
"keywords": [
|