@x12i/diagrams 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,58 +1,25 @@
1
+ import { D as DiagramDocument, N as NodeKind, a as NodeStatus, L as LayoutDirection } from './messages-ZCyCfyO0.js';
2
+ export { A as Alignment, C as COLLAPSED_HEIGHT, b as ConnectOptions, c as ConnectionCheck, d as ConnectionRejection, e as ConnectionRules, f as DEFAULT_NODE_SIZE, g as DIAGRAM_KINDS, h as DIAGRAM_VERSION, i as DiagramConnection, j as DiagramEdge, k as DiagramFragment, l as DiagramImportError, m as DiagramIndex, n as DiagramIssue, o as DiagramKind, p as DiagramMessages, q as DiagramMessagesOverride, r as DiagramMigration, s as DiagramMutationError, t as DiagramNode, u as DiagramPalette, v as DiagramPaletteOverride, E as EDGE_KINDS, w as EdgeGeometry, x as EdgeKind, y as EdgePatch, z as EdgePath, B as EdgePathInput, F as ExportJsonOptions, G as FocusDirection, H as GRID_SIZE, I as GeometryContext, J as GeometryOptions, K as GroupOptions, M as HistoryAction, O as HistoryOptions, P as HistoryState, Q as ImportErrorCode, R as ImportOptions, S as ImportResult, T as IssueCode, U as IssueSeverity, V as LayoutAlgorithm, W as LayoutOptions, X as LayoutResult, Y as LayoutSpacing, Z as Message, _ as MessageValues, $ as MutationErrorCode, a0 as NODE_KINDS, a1 as NODE_STATUSES, a2 as NewEdge, a3 as NewNode, a4 as NodePatch, a5 as PasteOptions, a6 as PasteResult, a7 as Point, a8 as PortPlacement, a9 as Position, aa as ReadingOrderOptions, ab as Rect, ac as RemoveOptions, ad as Side, ae as Size, af as StatusPalette, ag as SvgAttributes, ah as SvgElement, ai as SvgOptions, aj as TEXT_METRICS, ak as ValidateOptions, al as ValidationResult, am as addNode, an as alignNodes, ao as applyLayout, ap as buildIndex, aq as canRedo, ar as canUndo, as as checkConnection, at as computeEdgePath, au as connect, av as createDiagram, aw as createGeometryContext, ax as createHistory, ay as createNode, az as defaultMessages, aA as defaultPalette, aB as defineDiagram, aC as diagramToSvg, aD as diagramToSvgTree, aE as directionSides, aF as disconnect, aG as distributeNodes, aH as duplicateNodes, aI as escapeXml, aJ as estimateTextWidth, aK as exportDiagramJson, aL as exportDiagramSvg, aM as extractFragment, aN as findCycle, aO as findDirectionalNeighbor, aP as formatMessage, aQ as getAbsoluteBounds, aR as getAbsolutePosition, aS as getAbsolutePositions, aT as getAncestors, aU as getDescendants, aV as getDocumentBounds, aW as getEdgeGeometry, aX as getNeighbors, aY as getNodeBounds, aZ as getNodeSize, a_ as getPortPlacements, a$ as getReadingOrder, b0 as getRoots, b1 as groupNodes, b2 as hasPath, b3 as historyReducer, b4 as importDiagram, b5 as isContainerKind, b6 as isHorizontal, b7 as isSafeImageUrl, b8 as layoutDiagram, b9 as layoutedDiagram, ba as mirrorDirection, bb as moveNodes, bc as nextEdgeId, bd as nextNodeId, be as pasteFragment, bf as portTypesCompatible, bg as rectCenter, bh as rectContainsPoint, bi as rectsIntersect, bj as removeEdges, bk as removeNode, bl as removeNodes, bm as resizeNode, bn as resolveConnectionRules, bo as resolveMessages, bp as resolvePalette, bq as serializeSvg, br as setNodeParent, bs as sideAnchor, bt as sideVector, bu as snapPoint, bv as snapValue, bw as topologicalOrder, bx as translateNodes, by as ungroupNode, bz as unionRects, bA as updateEdge, bB as updateNode, bC as validateDiagram, bD as wrapText } from './messages-ZCyCfyO0.js';
3
+
1
4
  /**
2
- * The kit's own diagram document (spec section 10). It is versioned JSON, so
3
- * the node canvas engine can change without breaking saved diagrams.
5
+ * Id utilities. They are deterministic where it matters (`nextId`), so
6
+ * documents built by the editor stay diffable and tests stay stable.
4
7
  */
5
- declare const DIAGRAM_VERSION = 1;
6
- /** The node library. Every node reads kit tokens. */
7
- type NodeKind = "start" | "end" | "task" | "decision" | "group" | "note" | "image" | "entity" | "code" | "chart" | "agent" | "subflow";
8
- /** Status colors match the rest of the kit: a status means the same in a badge, a chart and a node. */
9
- type NodeStatus = "neutral" | "success" | "warning" | "danger" | "info";
10
- type EdgeKind = "straight" | "bezier" | "step" | "smooth-step";
11
- interface Position {
12
- x: number;
13
- y: number;
8
+ /** A random id such as `node-k3j9x2ab`. Not for tests; use `nextId` there. */
9
+ declare function generateId(prefix?: string, random?: () => number): string;
10
+ /** The smallest `prefix1`, `prefix2`, ... that is not taken. */
11
+ declare function nextId(taken: Iterable<string>, prefix: string): string;
12
+ interface IdAllocator {
13
+ /** Returns a new id and reserves it. */
14
+ next(prefix: string): string;
15
+ /** Marks an id as used. */
16
+ reserve(id: string): void;
17
+ has(id: string): boolean;
14
18
  }
15
- interface DiagramNode {
16
- id: string;
17
- kind: NodeKind;
18
- /** The text read aloud in the outline. Pass a translated string. */
19
- label: string;
20
- position: Position;
21
- status?: NodeStatus;
22
- /** Set on children of a group or subflow. */
23
- parentId?: string;
24
- width?: number;
25
- height?: number;
26
- /** Typed handles, for connection validation. */
27
- ports?: Array<{
28
- id: string;
29
- direction: "in" | "out";
30
- type?: string;
31
- }>;
32
- /** Free-form payload for custom node bodies, such as a ChartSpec for a chart node. */
33
- data?: Record<string, unknown>;
34
- }
35
- interface DiagramEdge {
36
- id: string;
37
- source: string;
38
- target: string;
39
- sourcePort?: string;
40
- targetPort?: string;
41
- kind?: EdgeKind;
42
- label?: string;
43
- /** Draw arrowheads at both ends. */
44
- bidirectional?: boolean;
45
- animated?: boolean;
46
- }
47
- interface DiagramDocument {
48
- version: typeof DIAGRAM_VERSION;
49
- /** Every diagram has a title that states what it shows. */
50
- title: string;
51
- nodes: DiagramNode[];
52
- edges: DiagramEdge[];
53
- }
54
- /** Identity helper for authoring-time type checking. */
55
- declare function defineDiagram(document: DiagramDocument): DiagramDocument;
19
+ /** Hands out unique ids in bulk without rescanning the taken set each time. */
20
+ declare function createIdAllocator(taken?: Iterable<string>): IdAllocator;
21
+ /** The readable stem of an id: `task12` becomes `task`, `a-copy` stays. Falls back to `fallback`. */
22
+ declare function idStem(id: string, fallback: string): string;
56
23
 
57
24
  interface OutlineOptions {
58
25
  /** Joins labels along a path. Pass a translated word. Defaults to "to". */
@@ -68,5 +35,51 @@ interface OutlineOptions {
68
35
  */
69
36
  declare function diagramToOutline(diagram: DiagramDocument, { connector, maxPaths }?: OutlineOptions): string[];
70
37
 
71
- export { DIAGRAM_VERSION, defineDiagram, diagramToOutline };
72
- export type { DiagramDocument, DiagramEdge, DiagramNode, EdgeKind, NodeKind, NodeStatus, OutlineOptions, Position };
38
+ interface OutlineConnection {
39
+ edgeId: string;
40
+ /** The node at the other end. */
41
+ nodeId: string;
42
+ /** That node's label. */
43
+ label: string;
44
+ /** The edge's own label, if it has one (for example "yes" or "no"). */
45
+ edgeLabel?: string;
46
+ }
47
+ /** One node of the structured outline. Groups hold their children in `children`. */
48
+ interface OutlineItem {
49
+ id: string;
50
+ label: string;
51
+ kind: NodeKind;
52
+ status?: NodeStatus;
53
+ description?: string;
54
+ /** Edges that arrive at this node, with the node each comes from. */
55
+ incoming: OutlineConnection[];
56
+ /** Edges that leave this node, with the node each goes to. */
57
+ outgoing: OutlineConnection[];
58
+ children: OutlineItem[];
59
+ }
60
+ interface OutlineTreeOptions {
61
+ /** Orders siblings the way the canvas orders Tab stops. Defaults to `TB`. */
62
+ direction?: LayoutDirection;
63
+ rtl?: boolean;
64
+ }
65
+ /**
66
+ * The structured counterpart of `diagramToOutline`: every node once, nested
67
+ * by group, in reading order, each with the nodes it connects to and from.
68
+ * The `DiagramOutline` component renders it as a nested list.
69
+ */
70
+ declare function diagramToOutlineTree(doc: DiagramDocument, options?: OutlineTreeOptions): OutlineItem[];
71
+ /** What a screen reader needs to name a node: its kind, label and how many connections it has. */
72
+ interface NodeSummary {
73
+ id: string;
74
+ kind: NodeKind;
75
+ label: string;
76
+ incoming: number;
77
+ outgoing: number;
78
+ status?: NodeStatus;
79
+ description?: string;
80
+ }
81
+ /** Summaries for every node, keyed by id. Cheap to build once per render. */
82
+ declare function summarizeNodes(doc: DiagramDocument): Map<string, NodeSummary>;
83
+
84
+ export { DiagramDocument, LayoutDirection, NodeKind, NodeStatus, createIdAllocator, diagramToOutline, diagramToOutlineTree, generateId, idStem, nextId, summarizeNodes };
85
+ export type { IdAllocator, NodeSummary, OutlineConnection, OutlineItem, OutlineOptions, OutlineTreeOptions };
package/dist/index.js CHANGED
@@ -1,46 +1,205 @@
1
- // src/schema.ts
2
- var DIAGRAM_VERSION = 1;
3
- function defineDiagram(document) {
4
- return document;
5
- }
6
-
7
- // src/outline.ts
8
- function diagramToOutline(diagram, { connector = "to", maxPaths = 100 } = {}) {
9
- const labels = new Map(diagram.nodes.map((node) => [node.id, node.label]));
10
- const outgoing = /* @__PURE__ */ new Map();
11
- const hasIncoming = /* @__PURE__ */ new Set();
12
- for (const edge of diagram.edges) {
13
- if (!labels.has(edge.source) || !labels.has(edge.target)) continue;
14
- outgoing.set(edge.source, [...outgoing.get(edge.source) ?? [], edge.target]);
15
- hasIncoming.add(edge.target);
16
- }
17
- const lines = [];
18
- const visited = /* @__PURE__ */ new Set();
19
- const label = (id) => labels.get(id) ?? id;
20
- const sentence = (ids) => ids.map(label).join(` ${connector} `);
21
- const walk = (id, trail) => {
22
- if (lines.length >= maxPaths) return;
23
- visited.add(id);
24
- const path = [...trail, id];
25
- const next = outgoing.get(id) ?? [];
26
- if (next.length === 0) {
27
- lines.push(sentence(path));
28
- return;
29
- }
30
- for (const target of next) {
31
- if (path.includes(target)) lines.push(sentence([...path, target]));
32
- else walk(target, path);
33
- }
34
- };
35
- for (const node of diagram.nodes) {
36
- if (!hasIncoming.has(node.id)) walk(node.id, []);
37
- }
38
- for (const node of diagram.nodes) {
39
- if (!visited.has(node.id)) walk(node.id, []);
40
- }
41
- return lines;
42
- }
43
-
44
- export { DIAGRAM_VERSION, defineDiagram, diagramToOutline };
45
- //# sourceMappingURL=index.js.map
1
+ import {
2
+ COLLAPSED_HEIGHT,
3
+ DEFAULT_NODE_SIZE,
4
+ DIAGRAM_KINDS,
5
+ DIAGRAM_VERSION,
6
+ DiagramImportError,
7
+ DiagramMutationError,
8
+ EDGE_KINDS,
9
+ GRID_SIZE,
10
+ NODE_KINDS,
11
+ NODE_STATUSES,
12
+ TEXT_METRICS,
13
+ addNode,
14
+ alignNodes,
15
+ applyLayout,
16
+ buildIndex,
17
+ canRedo,
18
+ canUndo,
19
+ checkConnection,
20
+ computeEdgePath,
21
+ connect,
22
+ createDiagram,
23
+ createGeometryContext,
24
+ createHistory,
25
+ createIdAllocator,
26
+ createNode,
27
+ defaultMessages,
28
+ defaultPalette,
29
+ defineDiagram,
30
+ diagramToOutline,
31
+ diagramToOutlineTree,
32
+ diagramToSvg,
33
+ diagramToSvgTree,
34
+ directionSides,
35
+ disconnect,
36
+ distributeNodes,
37
+ duplicateNodes,
38
+ escapeXml,
39
+ estimateTextWidth,
40
+ exportDiagramJson,
41
+ exportDiagramSvg,
42
+ extractFragment,
43
+ findCycle,
44
+ findDirectionalNeighbor,
45
+ formatMessage,
46
+ generateId,
47
+ getAbsoluteBounds,
48
+ getAbsolutePosition,
49
+ getAbsolutePositions,
50
+ getAncestors,
51
+ getDescendants,
52
+ getDocumentBounds,
53
+ getEdgeGeometry,
54
+ getNeighbors,
55
+ getNodeBounds,
56
+ getNodeSize,
57
+ getPortPlacements,
58
+ getReadingOrder,
59
+ getRoots,
60
+ groupNodes,
61
+ hasPath,
62
+ historyReducer,
63
+ idStem,
64
+ importDiagram,
65
+ isContainerKind,
66
+ isHorizontal,
67
+ isSafeImageUrl,
68
+ layoutDiagram,
69
+ layoutedDiagram,
70
+ mirrorDirection,
71
+ moveNodes,
72
+ nextEdgeId,
73
+ nextId,
74
+ nextNodeId,
75
+ pasteFragment,
76
+ portTypesCompatible,
77
+ rectCenter,
78
+ rectContainsPoint,
79
+ rectsIntersect,
80
+ removeEdges,
81
+ removeNode,
82
+ removeNodes,
83
+ resizeNode,
84
+ resolveConnectionRules,
85
+ resolveMessages,
86
+ resolvePalette,
87
+ serializeSvg,
88
+ setNodeParent,
89
+ sideAnchor,
90
+ sideVector,
91
+ snapPoint,
92
+ snapValue,
93
+ summarizeNodes,
94
+ topologicalOrder,
95
+ translateNodes,
96
+ ungroupNode,
97
+ unionRects,
98
+ updateEdge,
99
+ updateNode,
100
+ validateDiagram,
101
+ wrapText
102
+ } from "./chunk-3DJFQRU3.js";
103
+ export {
104
+ COLLAPSED_HEIGHT,
105
+ DEFAULT_NODE_SIZE,
106
+ DIAGRAM_KINDS,
107
+ DIAGRAM_VERSION,
108
+ DiagramImportError,
109
+ DiagramMutationError,
110
+ EDGE_KINDS,
111
+ GRID_SIZE,
112
+ NODE_KINDS,
113
+ NODE_STATUSES,
114
+ TEXT_METRICS,
115
+ addNode,
116
+ alignNodes,
117
+ applyLayout,
118
+ buildIndex,
119
+ canRedo,
120
+ canUndo,
121
+ checkConnection,
122
+ computeEdgePath,
123
+ connect,
124
+ createDiagram,
125
+ createGeometryContext,
126
+ createHistory,
127
+ createIdAllocator,
128
+ createNode,
129
+ defaultMessages,
130
+ defaultPalette,
131
+ defineDiagram,
132
+ diagramToOutline,
133
+ diagramToOutlineTree,
134
+ diagramToSvg,
135
+ diagramToSvgTree,
136
+ directionSides,
137
+ disconnect,
138
+ distributeNodes,
139
+ duplicateNodes,
140
+ escapeXml,
141
+ estimateTextWidth,
142
+ exportDiagramJson,
143
+ exportDiagramSvg,
144
+ extractFragment,
145
+ findCycle,
146
+ findDirectionalNeighbor,
147
+ formatMessage,
148
+ generateId,
149
+ getAbsoluteBounds,
150
+ getAbsolutePosition,
151
+ getAbsolutePositions,
152
+ getAncestors,
153
+ getDescendants,
154
+ getDocumentBounds,
155
+ getEdgeGeometry,
156
+ getNeighbors,
157
+ getNodeBounds,
158
+ getNodeSize,
159
+ getPortPlacements,
160
+ getReadingOrder,
161
+ getRoots,
162
+ groupNodes,
163
+ hasPath,
164
+ historyReducer,
165
+ idStem,
166
+ importDiagram,
167
+ isContainerKind,
168
+ isHorizontal,
169
+ isSafeImageUrl,
170
+ layoutDiagram,
171
+ layoutedDiagram,
172
+ mirrorDirection,
173
+ moveNodes,
174
+ nextEdgeId,
175
+ nextId,
176
+ nextNodeId,
177
+ pasteFragment,
178
+ portTypesCompatible,
179
+ rectCenter,
180
+ rectContainsPoint,
181
+ rectsIntersect,
182
+ removeEdges,
183
+ removeNode,
184
+ removeNodes,
185
+ resizeNode,
186
+ resolveConnectionRules,
187
+ resolveMessages,
188
+ resolvePalette,
189
+ serializeSvg,
190
+ setNodeParent,
191
+ sideAnchor,
192
+ sideVector,
193
+ snapPoint,
194
+ snapValue,
195
+ summarizeNodes,
196
+ topologicalOrder,
197
+ translateNodes,
198
+ ungroupNode,
199
+ unionRects,
200
+ updateEdge,
201
+ updateNode,
202
+ validateDiagram,
203
+ wrapText
204
+ };
46
205
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema.ts","../src/outline.ts"],"names":[],"mappings":";AAKO,IAAM,eAAA,GAAkB;AAkExB,SAAS,cAAc,QAAA,EAA4C;AACxE,EAAA,OAAO,QAAA;AACT;;;AC1DO,SAAS,gBAAA,CACd,SACA,EAAE,SAAA,GAAY,MAAM,QAAA,GAAW,GAAA,EAAI,GAAoB,EAAC,EAC9C;AACV,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,OAAA,CAAQ,MAAM,GAAA,CAAI,CAAC,IAAA,KAAS,CAAC,IAAA,CAAK,EAAA,EAAI,IAAA,CAAK,KAAK,CAAC,CAAC,CAAA;AACzE,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAsB;AAC3C,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AAEpC,EAAA,KAAA,MAAW,IAAA,IAAQ,QAAQ,KAAA,EAAO;AAChC,IAAA,IAAI,CAAC,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,IAAK,CAAC,MAAA,CAAO,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,EAAG;AAC1D,IAAA,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAA,EAAQ,CAAC,GAAI,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,IAAK,EAAC,EAAI,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7E,IAAA,WAAA,CAAY,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,EAC7B;AAEA,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,QAAQ,CAAC,EAAA,KAAe,MAAA,CAAO,GAAA,CAAI,EAAE,CAAA,IAAK,EAAA;AAChD,EAAA,MAAM,QAAA,GAAW,CAAC,GAAA,KAAkB,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,CAAG,CAAA;AAGxE,EAAA,MAAM,IAAA,GAAO,CAAC,EAAA,EAAY,KAAA,KAAoB;AAC5C,IAAA,IAAI,KAAA,CAAM,UAAU,QAAA,EAAU;AAC9B,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,IAAA,MAAM,IAAA,GAAO,CAAC,GAAG,KAAA,EAAO,EAAE,CAAA;AAC1B,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,EAAE,KAAK,EAAC;AAElC,IAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,MAAA,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,IAAI,CAAC,CAAA;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,UAAU,IAAA,EAAM;AACzB,MAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,CAAC,GAAG,IAAA,EAAM,MAAM,CAAC,CAAC,CAAA;AAAA,WAC5D,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,IACxB;AAAA,EACF,CAAA;AAEA,EAAA,KAAA,MAAW,IAAA,IAAQ,QAAQ,KAAA,EAAO;AAChC,IAAA,IAAI,CAAC,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,EAAE,GAAG,IAAA,CAAK,IAAA,CAAK,EAAA,EAAI,EAAE,CAAA;AAAA,EACjD;AAGA,EAAA,KAAA,MAAW,IAAA,IAAQ,QAAQ,KAAA,EAAO;AAChC,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,EAAE,GAAG,IAAA,CAAK,IAAA,CAAK,EAAA,EAAI,EAAE,CAAA;AAAA,EAC7C;AAEA,EAAA,OAAO,KAAA;AACT","file":"index.js","sourcesContent":["/**\r\n * The kit's own diagram document (spec section 10). It is versioned JSON, so\r\n * the node canvas engine can change without breaking saved diagrams.\r\n */\r\n\r\nexport const DIAGRAM_VERSION = 1;\r\n\r\n/** The node library. Every node reads kit tokens. */\r\nexport type NodeKind =\r\n | \"start\"\r\n | \"end\"\r\n | \"task\"\r\n | \"decision\"\r\n | \"group\"\r\n | \"note\"\r\n | \"image\"\r\n | \"entity\"\r\n | \"code\"\r\n | \"chart\"\r\n | \"agent\"\r\n | \"subflow\";\r\n\r\n/** Status colors match the rest of the kit: a status means the same in a badge, a chart and a node. */\r\nexport type NodeStatus = \"neutral\" | \"success\" | \"warning\" | \"danger\" | \"info\";\r\n\r\nexport type EdgeKind = \"straight\" | \"bezier\" | \"step\" | \"smooth-step\";\r\n\r\nexport interface Position {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface DiagramNode {\r\n id: string;\r\n kind: NodeKind;\r\n /** The text read aloud in the outline. Pass a translated string. */\r\n label: string;\r\n position: Position;\r\n status?: NodeStatus;\r\n /** Set on children of a group or subflow. */\r\n parentId?: string;\r\n width?: number;\r\n height?: number;\r\n /** Typed handles, for connection validation. */\r\n ports?: Array<{ id: string; direction: \"in\" | \"out\"; type?: string }>;\r\n /** Free-form payload for custom node bodies, such as a ChartSpec for a chart node. */\r\n data?: Record<string, unknown>;\r\n}\r\n\r\nexport interface DiagramEdge {\r\n id: string;\r\n source: string;\r\n target: string;\r\n sourcePort?: string;\r\n targetPort?: string;\r\n kind?: EdgeKind;\r\n label?: string;\r\n /** Draw arrowheads at both ends. */\r\n bidirectional?: boolean;\r\n animated?: boolean;\r\n}\r\n\r\nexport interface DiagramDocument {\r\n version: typeof DIAGRAM_VERSION;\r\n /** Every diagram has a title that states what it shows. */\r\n title: string;\r\n nodes: DiagramNode[];\r\n edges: DiagramEdge[];\r\n}\r\n\r\n/** Identity helper for authoring-time type checking. */\r\nexport function defineDiagram(document: DiagramDocument): DiagramDocument {\r\n return document;\r\n}\r\n","import type { DiagramDocument } from \"./schema\";\r\n\r\nexport interface OutlineOptions {\r\n /** Joins labels along a path. Pass a translated word. Defaults to \"to\". */\r\n connector?: string;\r\n /** Stop after this many paths so a dense graph cannot flood the outline. */\r\n maxPaths?: number;\r\n}\r\n\r\n/**\r\n * Generates the text outline that makes a diagram readable by screen readers:\r\n * one line per path through the graph, such as \"Start to Review to Approve\".\r\n * Nodes with no connections get a line of their own, and a path that loops back\r\n * ends with the node it returns to.\r\n */\r\nexport function diagramToOutline(\r\n diagram: DiagramDocument,\r\n { connector = \"to\", maxPaths = 100 }: OutlineOptions = {},\r\n): string[] {\r\n const labels = new Map(diagram.nodes.map((node) => [node.id, node.label]));\r\n const outgoing = new Map<string, string[]>();\r\n const hasIncoming = new Set<string>();\r\n\r\n for (const edge of diagram.edges) {\r\n if (!labels.has(edge.source) || !labels.has(edge.target)) continue;\r\n outgoing.set(edge.source, [...(outgoing.get(edge.source) ?? []), edge.target]);\r\n hasIncoming.add(edge.target);\r\n }\r\n\r\n const lines: string[] = [];\r\n const visited = new Set<string>();\r\n const label = (id: string) => labels.get(id) ?? id;\r\n const sentence = (ids: string[]) => ids.map(label).join(` ${connector} `);\r\n\r\n /** `trail` holds the ids on the path so far, not including `id`. */\r\n const walk = (id: string, trail: string[]) => {\r\n if (lines.length >= maxPaths) return;\r\n visited.add(id);\r\n const path = [...trail, id];\r\n const next = outgoing.get(id) ?? [];\r\n\r\n if (next.length === 0) {\r\n lines.push(sentence(path));\r\n return;\r\n }\r\n\r\n for (const target of next) {\r\n if (path.includes(target)) lines.push(sentence([...path, target]));\r\n else walk(target, path);\r\n }\r\n };\r\n\r\n for (const node of diagram.nodes) {\r\n if (!hasIncoming.has(node.id)) walk(node.id, []);\r\n }\r\n\r\n // Anything left over sits on a cycle with no entry point.\r\n for (const node of diagram.nodes) {\r\n if (!visited.has(node.id)) walk(node.id, []);\r\n }\r\n\r\n return lines;\r\n}\r\n"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}