@xenolithengine/graph-core 0.7.0-beta.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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -0
  3. package/dist/command-bus.d.ts +56 -0
  4. package/dist/command-bus.d.ts.map +1 -0
  5. package/dist/command-bus.js +180 -0
  6. package/dist/command-bus.js.map +1 -0
  7. package/dist/commands-comment.d.ts +52 -0
  8. package/dist/commands-comment.d.ts.map +1 -0
  9. package/dist/commands-comment.js +92 -0
  10. package/dist/commands-comment.js.map +1 -0
  11. package/dist/commands-mut.d.ts +58 -0
  12. package/dist/commands-mut.d.ts.map +1 -0
  13. package/dist/commands-mut.js +119 -0
  14. package/dist/commands-mut.js.map +1 -0
  15. package/dist/commands.d.ts +36 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +72 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/comment-spatial.d.ts +20 -0
  20. package/dist/comment-spatial.d.ts.map +1 -0
  21. package/dist/comment-spatial.js +21 -0
  22. package/dist/comment-spatial.js.map +1 -0
  23. package/dist/event-emitter.d.ts +15 -0
  24. package/dist/event-emitter.d.ts.map +1 -0
  25. package/dist/event-emitter.js +55 -0
  26. package/dist/event-emitter.js.map +1 -0
  27. package/dist/fuzzy.d.ts +17 -0
  28. package/dist/fuzzy.d.ts.map +1 -0
  29. package/dist/fuzzy.js +55 -0
  30. package/dist/fuzzy.js.map +1 -0
  31. package/dist/graph.d.ts +108 -0
  32. package/dist/graph.d.ts.map +1 -0
  33. package/dist/graph.js +141 -0
  34. package/dist/graph.js.map +1 -0
  35. package/dist/ids.d.ts +28 -0
  36. package/dist/ids.d.ts.map +1 -0
  37. package/dist/ids.js +31 -0
  38. package/dist/ids.js.map +1 -0
  39. package/dist/index.d.ts +35 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +20 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/macro.d.ts +120 -0
  44. package/dist/macro.d.ts.map +1 -0
  45. package/dist/macro.js +226 -0
  46. package/dist/macro.js.map +1 -0
  47. package/dist/node-registry.d.ts +101 -0
  48. package/dist/node-registry.d.ts.map +1 -0
  49. package/dist/node-registry.js +96 -0
  50. package/dist/node-registry.js.map +1 -0
  51. package/dist/reroute.d.ts +21 -0
  52. package/dist/reroute.d.ts.map +1 -0
  53. package/dist/reroute.js +40 -0
  54. package/dist/reroute.js.map +1 -0
  55. package/dist/selection.d.ts +17 -0
  56. package/dist/selection.d.ts.map +1 -0
  57. package/dist/selection.js +56 -0
  58. package/dist/selection.js.map +1 -0
  59. package/dist/template-def.d.ts +113 -0
  60. package/dist/template-def.d.ts.map +1 -0
  61. package/dist/template-def.js +0 -0
  62. package/dist/template-def.js.map +1 -0
  63. package/dist/template-flatten.d.ts +38 -0
  64. package/dist/template-flatten.d.ts.map +1 -0
  65. package/dist/template-flatten.js +157 -0
  66. package/dist/template-flatten.js.map +1 -0
  67. package/dist/traversal.d.ts +27 -0
  68. package/dist/traversal.d.ts.map +1 -0
  69. package/dist/traversal.js +119 -0
  70. package/dist/traversal.js.map +1 -0
  71. package/dist/types-registry.d.ts +41 -0
  72. package/dist/types-registry.d.ts.map +1 -0
  73. package/dist/types-registry.js +60 -0
  74. package/dist/types-registry.js.map +1 -0
  75. package/dist/widget.d.ts +141 -0
  76. package/dist/widget.d.ts.map +1 -0
  77. package/dist/widget.js +112 -0
  78. package/dist/widget.js.map +1 -0
  79. package/package.json +55 -0
package/dist/graph.js ADDED
@@ -0,0 +1,141 @@
1
+ export class Graph {
2
+ #nodes = new Map();
3
+ #edges = new Map();
4
+ #comments = new Map();
5
+ #version = 0;
6
+ get version() { return this.#version; }
7
+ get nodeCount() { return this.#nodes.size; }
8
+ get edgeCount() { return this.#edges.size; }
9
+ get commentCount() { return this.#comments.size; }
10
+ getNode(id) { return this.#nodes.get(id); }
11
+ hasNode(id) { return this.#nodes.has(id); }
12
+ *nodes() {
13
+ for (const n of this.#nodes.values())
14
+ yield n;
15
+ }
16
+ getEdge(id) { return this.#edges.get(id); }
17
+ hasEdge(id) { return this.#edges.has(id); }
18
+ *edges() {
19
+ for (const e of this.#edges.values())
20
+ yield e;
21
+ }
22
+ getComment(id) { return this.#comments.get(id); }
23
+ hasComment(id) { return this.#comments.has(id); }
24
+ *comments() {
25
+ for (const c of this.#comments.values())
26
+ yield c;
27
+ }
28
+ /** @internal */
29
+ _addComment(comment) {
30
+ if (this.#comments.has(comment.id)) {
31
+ throw new Error(`Graph: duplicate comment id ${comment.id}`);
32
+ }
33
+ this.#comments.set(comment.id, comment);
34
+ this.#version++;
35
+ }
36
+ /** @internal */
37
+ _removeComment(id) {
38
+ const comment = this.#comments.get(id);
39
+ if (!comment)
40
+ return undefined;
41
+ this.#comments.delete(id);
42
+ this.#version++;
43
+ return comment;
44
+ }
45
+ /** @internal — patch mutable Comment fields in place (identity `id` is immutable). */
46
+ _patchComment(id, patch) {
47
+ const comment = this.#comments.get(id);
48
+ if (!comment)
49
+ return undefined;
50
+ if (patch.position !== undefined)
51
+ comment.position = patch.position;
52
+ if (patch.size !== undefined)
53
+ comment.size = patch.size;
54
+ if (patch.text !== undefined)
55
+ comment.text = patch.text;
56
+ if (patch.color !== undefined)
57
+ comment.color = patch.color;
58
+ this.#version++;
59
+ return comment;
60
+ }
61
+ /** @internal — call only from CommandBus-applied commands. */
62
+ _addNode(node) {
63
+ if (this.#nodes.has(node.id)) {
64
+ throw new Error(`Graph: duplicate node id ${node.id}`);
65
+ }
66
+ this.#nodes.set(node.id, node);
67
+ this.#version++;
68
+ }
69
+ /** @internal */
70
+ _removeNode(id) {
71
+ const node = this.#nodes.get(id);
72
+ if (!node)
73
+ return undefined;
74
+ this.#nodes.delete(id);
75
+ this.#version++;
76
+ return node;
77
+ }
78
+ /** @internal */
79
+ _addEdge(edge) {
80
+ if (this.#edges.has(edge.id)) {
81
+ throw new Error(`Graph: duplicate edge id ${edge.id}`);
82
+ }
83
+ this.#edges.set(edge.id, edge);
84
+ this.#version++;
85
+ }
86
+ /** @internal */
87
+ _removeEdge(id) {
88
+ const edge = this.#edges.get(id);
89
+ if (!edge)
90
+ return undefined;
91
+ this.#edges.delete(id);
92
+ this.#version++;
93
+ return edge;
94
+ }
95
+ /**
96
+ * @internal — patch a subset of mutable Node fields in place.
97
+ * Only `position`, `size`, `state`, and `type` may be patched; identity (`id`) and pin structure
98
+ * (`pins`) are immutable through this method by design. Returns the patched node (same reference)
99
+ * or undefined if the id is unknown.
100
+ */
101
+ _patchNode(id, patch) {
102
+ const node = this.#nodes.get(id);
103
+ if (!node)
104
+ return undefined;
105
+ if (patch.position !== undefined)
106
+ node.position = patch.position;
107
+ if (patch.size !== undefined)
108
+ node.size = patch.size;
109
+ if (patch.state !== undefined)
110
+ node.state = patch.state;
111
+ if (patch.type !== undefined)
112
+ node.type = patch.type;
113
+ this.#version++;
114
+ return node;
115
+ }
116
+ /** @internal — replace a node's pin list wholesale. Pruning edges incident to dropped pins is the
117
+ * caller's job (the SetNodePins command does it so the change is undoable). */
118
+ _setNodePins(id, pins) {
119
+ const node = this.#nodes.get(id);
120
+ if (!node)
121
+ return undefined;
122
+ node.pins = pins;
123
+ this.#version++;
124
+ return node;
125
+ }
126
+ /** @internal — replace a node's widget list wholesale. Per-widget `node.state[key]` values are
127
+ * NOT touched: re-adding a previously-removed widget under the same key restores its value.
128
+ * Use via the `SetNodeWidgets` command so the change is undoable. */
129
+ _setNodeWidgets(id, widgets) {
130
+ const node = this.#nodes.get(id);
131
+ if (!node)
132
+ return undefined;
133
+ if (widgets && widgets.length > 0)
134
+ node.widgets = widgets;
135
+ else
136
+ delete node.widgets;
137
+ this.#version++;
138
+ return node;
139
+ }
140
+ }
141
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
package/dist/ids.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ declare const NodeIdBrand: unique symbol;
2
+ declare const EdgeIdBrand: unique symbol;
3
+ declare const PinIdBrand: unique symbol;
4
+ declare const CommentIdBrand: unique symbol;
5
+ declare const TypeIdBrand: unique symbol;
6
+ export type NodeId = string & {
7
+ readonly [NodeIdBrand]: true;
8
+ };
9
+ export type EdgeId = string & {
10
+ readonly [EdgeIdBrand]: true;
11
+ };
12
+ export type PinId = string & {
13
+ readonly [PinIdBrand]: true;
14
+ };
15
+ export type CommentId = string & {
16
+ readonly [CommentIdBrand]: true;
17
+ };
18
+ export type TypeId = string & {
19
+ readonly [TypeIdBrand]: true;
20
+ };
21
+ export declare function createNodeId(): NodeId;
22
+ export declare function createEdgeId(): EdgeId;
23
+ export declare function createPinId(): PinId;
24
+ export declare function createCommentId(): CommentId;
25
+ export declare function createTypeId(value: string): TypeId;
26
+ export declare function isUuidV7(value: unknown): boolean;
27
+ export {};
28
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,WAAW,EAAE,OAAO,MAAM,CAAA;AACxC,OAAO,CAAC,MAAM,WAAW,EAAE,OAAO,MAAM,CAAA;AACxC,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAA;AACvC,OAAO,CAAC,MAAM,cAAc,EAAE,OAAO,MAAM,CAAA;AAC3C,OAAO,CAAC,MAAM,WAAW,EAAE,OAAO,MAAM,CAAA;AAExC,MAAM,MAAM,MAAM,GAAM,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AACjE,MAAM,MAAM,MAAM,GAAM,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AACjE,MAAM,MAAM,KAAK,GAAO,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AAChE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AACpE,MAAM,MAAM,MAAM,GAAM,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AA6BjE,wBAAgB,YAAY,IAAI,MAAM,CAAoC;AAC1E,wBAAgB,YAAY,IAAI,MAAM,CAAoC;AAC1E,wBAAgB,WAAW,IAAI,KAAK,CAAqC;AACzE,wBAAgB,eAAe,IAAI,SAAS,CAAiC;AAC7E,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAA2B;AAE9E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhD"}
package/dist/ids.js ADDED
@@ -0,0 +1,31 @@
1
+ const UUID_V7_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2
+ let lastIssuedMs = 0n;
3
+ function uuidV7() {
4
+ const now = BigInt(Date.now());
5
+ const ms = now > lastIssuedMs ? now : lastIssuedMs + 1n;
6
+ lastIssuedMs = ms;
7
+ const bytes = new Uint8Array(16);
8
+ bytes[0] = Number((ms >> 40n) & 0xffn);
9
+ bytes[1] = Number((ms >> 32n) & 0xffn);
10
+ bytes[2] = Number((ms >> 24n) & 0xffn);
11
+ bytes[3] = Number((ms >> 16n) & 0xffn);
12
+ bytes[4] = Number((ms >> 8n) & 0xffn);
13
+ bytes[5] = Number(ms & 0xffn);
14
+ crypto.getRandomValues(bytes.subarray(6));
15
+ bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x70;
16
+ bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
17
+ const hex = [];
18
+ for (let i = 0; i < 16; i++)
19
+ hex.push((bytes[i] ?? 0).toString(16).padStart(2, '0'));
20
+ const h = hex.join('');
21
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
22
+ }
23
+ export function createNodeId() { return uuidV7(); }
24
+ export function createEdgeId() { return uuidV7(); }
25
+ export function createPinId() { return uuidV7(); }
26
+ export function createCommentId() { return uuidV7(); }
27
+ export function createTypeId(value) { return value; }
28
+ export function isUuidV7(value) {
29
+ return typeof value === 'string' && UUID_V7_PATTERN.test(value);
30
+ }
31
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export declare const VERSION = "0.7.0-beta.0";
2
+ export { EventEmitter } from './event-emitter.js';
3
+ export type { EventMap, Listener, Unsubscribe, ErrorListener } from './event-emitter.js';
4
+ export { createNodeId, createEdgeId, createPinId, createCommentId, createTypeId, isUuidV7, } from './ids.js';
5
+ export type { NodeId, EdgeId, PinId, CommentId, TypeId } from './ids.js';
6
+ export { Graph } from './graph.js';
7
+ export type { Node, Edge, Pin, Comment, Vec2, PinKind, PinDirection, NodeGlyph } from './graph.js';
8
+ export { incomers, outgoers, connectedEdges, roots, leaves, topoOrder, wouldCreateCycle, reachableFrom } from './traversal.js';
9
+ export { CommandBus } from './command-bus.js';
10
+ export type { Command, CommandContext, CommandBusOptions, CoreEvents } from './command-bus.js';
11
+ export { AddNode, RemoveNode, ConnectPins, DisconnectEdge } from './commands.js';
12
+ export type { RemoveNodeUndo } from './commands.js';
13
+ export { MoveNode, ResizeNode, SetNodeState, SetNodePins, SetNodeWidgets } from './commands-mut.js';
14
+ export type { SetNodePinsUndo, SetNodeWidgetsUndo } from './commands-mut.js';
15
+ export { AddComment, RemoveComment, MoveComment, ResizeComment, SetCommentText } from './commands-comment.js';
16
+ export { nodesInsideComment } from './comment-spatial.js';
17
+ export type { PlacedNode, CommentRect } from './comment-spatial.js';
18
+ export { Selection } from './selection.js';
19
+ export type { SelectionMode, SelectionChange } from './selection.js';
20
+ export { NodeRegistry, migrateNodePayload } from './node-registry.js';
21
+ export type { NodeSchema, PinSchema, NodeSearchResult } from './node-registry.js';
22
+ export { TypeRegistry } from './types-registry.js';
23
+ export type { TypeDescriptor } from './types-registry.js';
24
+ export { fuzzyMatch } from './fuzzy.js';
25
+ export type { FuzzyMatch } from './fuzzy.js';
26
+ export { REROUTE_TYPE, isReroute, createReroute, REROUTE_NODE_TYPE, rerouteNodeSchema } from './reroute.js';
27
+ export { MACRO_TYPE, isMacro, createMacro, macroMembers, boundaryEdges, macroProxyPins, planMacroCollapse, planMacroExpand, flattenMacroProxies, disconnectedWidgetBoundPins } from './macro.js';
28
+ export type { MacroBoundary, MacroProxyPin, MacroProxyRecord, MacroCollapsePlan, MacroExpandPlan, Minters } from './macro.js';
29
+ export { TEMPLATE_INPUT_TYPE, TEMPLATE_OUTPUT_TYPE, TEMPLATE_INSTANCE_TYPE, isTemplateBoundary, isTemplateInstance, templateInterface, materializeInterface, planTemplateExtraction, planTemplateUnpack, templateDefContains, } from './template-def.js';
30
+ export type { TemplateDefId, TemplateDefinition, TemplateInterfacePin, TemplateMinters, TemplateExtraction, TemplateUnpackPlan, } from './template-def.js';
31
+ export { flattenTemplateInstance, flattenAllTemplateInstances } from './template-flatten.js';
32
+ export type { FlattenedTemplate, PinRef } from './template-flatten.js';
33
+ export { defaultWidgetValue, widgetValue, clampWidgetValue, comboOptions, widgetVisibility, widgetBindKey, widgetIsVisible } from './widget.js';
34
+ export type { WidgetSpec, WidgetType, WidgetStyle, ComboOption, ComboOptionResolved } from './widget.js';
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ export const VERSION = '0.7.0-beta.0';
2
+ export { EventEmitter } from './event-emitter.js';
3
+ export { createNodeId, createEdgeId, createPinId, createCommentId, createTypeId, isUuidV7, } from './ids.js';
4
+ export { Graph } from './graph.js';
5
+ export { incomers, outgoers, connectedEdges, roots, leaves, topoOrder, wouldCreateCycle, reachableFrom } from './traversal.js';
6
+ export { CommandBus } from './command-bus.js';
7
+ export { AddNode, RemoveNode, ConnectPins, DisconnectEdge } from './commands.js';
8
+ export { MoveNode, ResizeNode, SetNodeState, SetNodePins, SetNodeWidgets } from './commands-mut.js';
9
+ export { AddComment, RemoveComment, MoveComment, ResizeComment, SetCommentText } from './commands-comment.js';
10
+ export { nodesInsideComment } from './comment-spatial.js';
11
+ export { Selection } from './selection.js';
12
+ export { NodeRegistry, migrateNodePayload } from './node-registry.js';
13
+ export { TypeRegistry } from './types-registry.js';
14
+ export { fuzzyMatch } from './fuzzy.js';
15
+ export { REROUTE_TYPE, isReroute, createReroute, REROUTE_NODE_TYPE, rerouteNodeSchema } from './reroute.js';
16
+ export { MACRO_TYPE, isMacro, createMacro, macroMembers, boundaryEdges, macroProxyPins, planMacroCollapse, planMacroExpand, flattenMacroProxies, disconnectedWidgetBoundPins } from './macro.js';
17
+ export { TEMPLATE_INPUT_TYPE, TEMPLATE_OUTPUT_TYPE, TEMPLATE_INSTANCE_TYPE, isTemplateBoundary, isTemplateInstance, templateInterface, materializeInterface, planTemplateExtraction, planTemplateUnpack, templateDefContains, } from './template-def.js';
18
+ export { flattenTemplateInstance, flattenAllTemplateInstances } from './template-flatten.js';
19
+ export { defaultWidgetValue, widgetValue, clampWidgetValue, comboOptions, widgetVisibility, widgetBindKey, widgetIsVisible } from './widget.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAA;AAErC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,YAAY,EACZ,QAAQ,GACT,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9H,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGhF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGnG,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC7G,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAGzD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAGvC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC3G,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAGhM,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,mBAAmB,CAAA;AAU1B,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAA;AAG5F,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,120 @@
1
+ import type { Edge, Node, Pin, Vec2 } from './graph.js';
2
+ import type { NodeId, PinId, EdgeId } from './ids.js';
3
+ /** Reserved node type for a macro — a group of nodes that collapses into a single compact node and
4
+ * expands back in place (inline, no drill-in subgraph). The graph stays flat: members live in the
5
+ * graph and are hidden while collapsed. `state.members` holds the member ids, `state.collapsed`
6
+ * the fold state. Boundary-crossing edges become the macro's proxy pins (see boundaryEdges). */
7
+ export declare const MACRO_TYPE = "Macro";
8
+ export declare function isMacro(node: {
9
+ type: string;
10
+ }): boolean;
11
+ /** Mint a collapsed macro node carrying its member ids. Pins are derived from boundary edges by the
12
+ * editor on collapse, so a fresh macro starts pinless. */
13
+ export declare function createMacro(position: Vec2, members: NodeId[]): Node;
14
+ /** Member ids of a macro node (empty for a non-macro or one with no members). */
15
+ export declare function macroMembers(node: Node): NodeId[];
16
+ export interface MacroBoundary {
17
+ /** Edges entering the group (from outside → a member): become the macro's input pins. */
18
+ inputs: Edge[];
19
+ /** Edges leaving the group (a member → outside): become the macro's output pins. */
20
+ outputs: Edge[];
21
+ /** Edges fully inside the group: hidden while collapsed, restored on expand. */
22
+ internal: Edge[];
23
+ }
24
+ export interface MacroProxyPin {
25
+ direction: 'in' | 'out';
26
+ /** The member node this proxy stands in for. */
27
+ memberNode: NodeId;
28
+ /** The member's own pin the boundary edges cross at. */
29
+ memberPin: PinId;
30
+ /** Boundary edges routed through this proxy (an in-pin may gather several feeds; an out-pin may
31
+ * fan out to several externals). */
32
+ edges: EdgeId[];
33
+ }
34
+ /** Collapse boundary edges into the macro's proxy pins: one input pin per distinct member IN-pin that
35
+ * receives an external feed, one output pin per distinct member OUT-pin that drives an external. Pin
36
+ * insertion order follows first appearance, so collapse is deterministic. */
37
+ export declare function macroProxyPins(boundary: MacroBoundary): MacroProxyPin[];
38
+ /** One restored-on-expand record per macro proxy edge: which fresh macro edge stands in for which
39
+ * original external↔member connection. Stored on the macro's state so expand can rebuild exactly. */
40
+ export interface MacroProxyRecord {
41
+ /** Id of the macro proxy edge (external↔macro) created on collapse. `null` for a LIFTED pin —
42
+ * a widget-bound member IN-pin that wasn't wire-fed at collapse time but was surfaced anyway
43
+ * so the user can wire to it later (UX parity with Template's open boundary pins). On a future
44
+ * connect-to-macro-pin while collapsed, the editor fills this in with the real edge id so
45
+ * expand rewires it correctly; while it stays null the pin is a no-op on expand. */
46
+ edgeId: EdgeId | null;
47
+ /** The macro's own proxy pin this crossing uses — fixed for the macro's lifetime, so collapse and
48
+ * expand just re-point the edge between this pin and the member pin without re-deriving pins. */
49
+ macroPin: PinId;
50
+ direction: 'in' | 'out';
51
+ externalNode: NodeId;
52
+ externalPin: PinId;
53
+ memberNode: NodeId;
54
+ memberPin: PinId;
55
+ }
56
+ export interface Minters {
57
+ pin: () => PinId;
58
+ edge: () => EdgeId;
59
+ }
60
+ export interface MacroCollapsePlan {
61
+ /** Proxy pins to give the macro node. */
62
+ pins: Pin[];
63
+ /** Boundary edges to remove (rewired onto the macro). */
64
+ disconnect: EdgeId[];
65
+ /** New external↔macro edges. */
66
+ connect: Edge[];
67
+ /** Restore map → macro.state for expand. */
68
+ proxyMap: MacroProxyRecord[];
69
+ }
70
+ export interface PlanMacroCollapseOpts {
71
+ /** Member IN-pins to expose on the macro even though no external edge crosses them yet —
72
+ * typically the widget-bound IN-pins discovered via `disconnectedWidgetBoundPins`. Each entry
73
+ * becomes a proxy IN-pin with a sentinel `proxyMap` record (`edgeId: null`) so the editor can
74
+ * finalise the bridge when the user later connects to it. Entries that overlap a wire-fed
75
+ * boundary pin are silently de-duplicated. */
76
+ liftPins?: ReadonlyArray<{
77
+ node: NodeId;
78
+ pin: PinId;
79
+ }>;
80
+ }
81
+ /** Plan a collapse: derive proxy pins from boundary crossings and rewire each boundary edge onto the
82
+ * macro (external↔member becomes external↔macro.proxyPin). Pure — the caller applies it through the
83
+ * command bus and persists `proxyMap` on the macro. `typeOf` resolves a member pin's wire type so
84
+ * the proxy pin carries it; `mint` supplies fresh pin/edge ids. */
85
+ export declare function planMacroCollapse(macroId: NodeId, members: NodeId[], edges: ReadonlyArray<Edge>, pinInfo: (node: NodeId, pin: PinId) => {
86
+ type: string;
87
+ label?: string;
88
+ }, mint: Minters, opts?: PlanMacroCollapseOpts): MacroCollapsePlan;
89
+ /** Find every widget-bound IN-pin on `member` that isn't already fed by an incoming edge — the
90
+ * set that needs to be LIFTED onto a macro on collapse so the widget surface survives. Pure;
91
+ * pass `hasIncomingEdge(pinId)` so the caller drives boundary-awareness from whatever index it
92
+ * has (graph.edges() pass, edge-by-node cache, anything cheap). Skips button widgets (no pin
93
+ * binding) and OUT-pins (display widgets — macro pins lift inputs only). */
94
+ export declare function disconnectedWidgetBoundPins(member: Node, hasIncomingEdge: (pinId: PinId) => boolean): Array<{
95
+ node: NodeId;
96
+ pin: PinId;
97
+ }>;
98
+ export interface MacroExpandPlan {
99
+ /** Macro proxy edges to remove. */
100
+ disconnect: EdgeId[];
101
+ /** Original external↔member edges to restore (fresh ids). */
102
+ connect: Edge[];
103
+ }
104
+ /** Plan an expand: drop every macro proxy edge and rebuild the original external↔member edges from
105
+ * the stored proxy map. Pure — caller applies it and strips the macro's proxy pins. */
106
+ export declare function planMacroExpand(proxyMap: ReadonlyArray<MacroProxyRecord>, mint: Minters): MacroExpandPlan;
107
+ /** Partition edges relative to a member set — the heart of macro pin-proxying. An edge with exactly
108
+ * one endpoint inside the group crosses the boundary (input if it enters, output if it leaves); both
109
+ * inside is internal; both outside is ignored. Order within each bucket follows input order. */
110
+ export declare function boundaryEdges(members: ReadonlySet<NodeId>, edges: ReadonlyArray<Edge>): MacroBoundary;
111
+ /** Flatten collapsed macros into their primitives for a host interpreter: drop every `Macro` node and
112
+ * remap any edge endpoint that lands on a macro proxy pin back to the member pin it bridges (via the
113
+ * macro's `state.proxyMap`). Recurses through nested macros (a member pin may itself be an inner
114
+ * macro's proxy pin). Pure — never mutates the inputs. Internal member↔member edges pass through
115
+ * untouched; the macro grouping becomes purely visual. */
116
+ export declare function flattenMacroProxies(nodes: ReadonlyArray<Node>, edges: ReadonlyArray<Edge>): {
117
+ nodes: Node[];
118
+ edges: Edge[];
119
+ };
120
+ //# sourceMappingURL=macro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macro.d.ts","sourceRoot":"","sources":["../src/macro.ts"],"names":[],"mappings":"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"}
package/dist/macro.js ADDED
@@ -0,0 +1,226 @@
1
+ import { createNodeId } from './ids.js';
2
+ import { widgetBindKey } from './widget.js';
3
+ /** Reserved node type for a macro — a group of nodes that collapses into a single compact node and
4
+ * expands back in place (inline, no drill-in subgraph). The graph stays flat: members live in the
5
+ * graph and are hidden while collapsed. `state.members` holds the member ids, `state.collapsed`
6
+ * the fold state. Boundary-crossing edges become the macro's proxy pins (see boundaryEdges). */
7
+ export const MACRO_TYPE = 'Macro';
8
+ export function isMacro(node) {
9
+ return node.type === MACRO_TYPE;
10
+ }
11
+ /** Mint a collapsed macro node carrying its member ids. Pins are derived from boundary edges by the
12
+ * editor on collapse, so a fresh macro starts pinless. */
13
+ export function createMacro(position, members) {
14
+ return {
15
+ id: createNodeId(),
16
+ type: MACRO_TYPE,
17
+ position,
18
+ state: { members: [...members], collapsed: true },
19
+ pins: [],
20
+ };
21
+ }
22
+ /** Member ids of a macro node (empty for a non-macro or one with no members). */
23
+ export function macroMembers(node) {
24
+ if (!isMacro(node))
25
+ return [];
26
+ const m = node.state['members'];
27
+ return Array.isArray(m) ? m : [];
28
+ }
29
+ /** Collapse boundary edges into the macro's proxy pins: one input pin per distinct member IN-pin that
30
+ * receives an external feed, one output pin per distinct member OUT-pin that drives an external. Pin
31
+ * insertion order follows first appearance, so collapse is deterministic. */
32
+ export function macroProxyPins(boundary) {
33
+ const order = [];
34
+ const byKey = new Map();
35
+ const add = (direction, node, pin, edge) => {
36
+ const key = `${direction}:${node}:${pin}`;
37
+ let proxy = byKey.get(key);
38
+ if (!proxy) {
39
+ proxy = { direction, memberNode: node, memberPin: pin, edges: [] };
40
+ byKey.set(key, proxy);
41
+ order.push(proxy);
42
+ }
43
+ proxy.edges.push(edge);
44
+ };
45
+ for (const e of boundary.inputs)
46
+ add('in', e.to.node, e.to.pin, e.id);
47
+ for (const e of boundary.outputs)
48
+ add('out', e.from.node, e.from.pin, e.id);
49
+ return order;
50
+ }
51
+ /** Plan a collapse: derive proxy pins from boundary crossings and rewire each boundary edge onto the
52
+ * macro (external↔member becomes external↔macro.proxyPin). Pure — the caller applies it through the
53
+ * command bus and persists `proxyMap` on the macro. `typeOf` resolves a member pin's wire type so
54
+ * the proxy pin carries it; `mint` supplies fresh pin/edge ids. */
55
+ export function planMacroCollapse(macroId, members, edges, pinInfo, mint, opts = {}) {
56
+ const boundary = boundaryEdges(new Set(members), edges);
57
+ const proxies = macroProxyPins(boundary);
58
+ const byId = new Map(edges.map((e) => [e.id, e]));
59
+ const pins = [];
60
+ const connect = [];
61
+ const disconnect = [];
62
+ const proxyMap = [];
63
+ for (const proxy of proxies) {
64
+ const pinId = mint.pin();
65
+ const info = pinInfo(proxy.memberNode, proxy.memberPin);
66
+ pins.push({
67
+ id: pinId,
68
+ kind: 'data',
69
+ direction: proxy.direction,
70
+ type: info.type,
71
+ multiple: proxy.direction === 'out',
72
+ ...(info.label !== undefined ? { label: info.label } : {}),
73
+ });
74
+ for (const beId of proxy.edges) {
75
+ const orig = byId.get(beId);
76
+ disconnect.push(beId);
77
+ const newId = mint.edge();
78
+ // input: external.out → macro.in ; output: macro.out → external.in
79
+ const external = proxy.direction === 'in' ? orig.from : orig.to;
80
+ const newEdge = proxy.direction === 'in'
81
+ ? { id: newId, from: { ...external }, to: { node: macroId, pin: pinId } }
82
+ : { id: newId, from: { node: macroId, pin: pinId }, to: { ...external } };
83
+ connect.push(newEdge);
84
+ proxyMap.push({
85
+ edgeId: newId,
86
+ macroPin: pinId,
87
+ direction: proxy.direction,
88
+ externalNode: external.node,
89
+ externalPin: external.pin,
90
+ memberNode: proxy.memberNode,
91
+ memberPin: proxy.memberPin,
92
+ });
93
+ }
94
+ }
95
+ // Lifted pins: surface free widget-bound IN-pins as macro IN proxies even though no boundary
96
+ // edge crosses them. De-dupe against wire-fed proxies so a pin that's already exposed via a
97
+ // real edge isn't doubled. `edgeId: null` marks the entry pending — editor finalises it on the
98
+ // first connect-to-macro-pin while collapsed.
99
+ const wiredMemberPins = new Set(proxies.filter((p) => p.direction === 'in').map((p) => String(p.memberPin)));
100
+ for (const lift of opts.liftPins ?? []) {
101
+ if (wiredMemberPins.has(String(lift.pin)))
102
+ continue;
103
+ wiredMemberPins.add(String(lift.pin));
104
+ const pinId = mint.pin();
105
+ const info = pinInfo(lift.node, lift.pin);
106
+ pins.push({
107
+ id: pinId,
108
+ kind: 'data',
109
+ direction: 'in',
110
+ type: info.type,
111
+ multiple: false,
112
+ ...(info.label !== undefined ? { label: info.label } : {}),
113
+ });
114
+ proxyMap.push({
115
+ edgeId: null,
116
+ macroPin: pinId,
117
+ direction: 'in',
118
+ externalNode: '', // filled in when user wires it
119
+ externalPin: '',
120
+ memberNode: lift.node,
121
+ memberPin: lift.pin,
122
+ });
123
+ }
124
+ return { pins, disconnect, connect, proxyMap };
125
+ }
126
+ /** Find every widget-bound IN-pin on `member` that isn't already fed by an incoming edge — the
127
+ * set that needs to be LIFTED onto a macro on collapse so the widget surface survives. Pure;
128
+ * pass `hasIncomingEdge(pinId)` so the caller drives boundary-awareness from whatever index it
129
+ * has (graph.edges() pass, edge-by-node cache, anything cheap). Skips button widgets (no pin
130
+ * binding) and OUT-pins (display widgets — macro pins lift inputs only). */
131
+ export function disconnectedWidgetBoundPins(member, hasIncomingEdge) {
132
+ const widgets = member.widgets;
133
+ if (!widgets || widgets.length === 0)
134
+ return [];
135
+ const out = [];
136
+ for (const w of widgets) {
137
+ const key = widgetBindKey(w);
138
+ if (key === undefined)
139
+ continue;
140
+ const pin = member.pins.find((p) => p.label === key || String(p.id) === key);
141
+ if (!pin || pin.direction !== 'in')
142
+ continue;
143
+ if (hasIncomingEdge(pin.id))
144
+ continue;
145
+ out.push({ node: member.id, pin: pin.id });
146
+ }
147
+ return out;
148
+ }
149
+ /** Plan an expand: drop every macro proxy edge and rebuild the original external↔member edges from
150
+ * the stored proxy map. Pure — caller applies it and strips the macro's proxy pins. */
151
+ export function planMacroExpand(proxyMap, mint) {
152
+ const disconnect = [];
153
+ const connect = [];
154
+ for (const r of proxyMap) {
155
+ // Lifted-but-never-wired pin (edgeId stayed null): no external edge to drop, no member edge
156
+ // to restore — the macro pin just disappears with the rest on expand. Skip entirely.
157
+ if (r.edgeId === null)
158
+ continue;
159
+ disconnect.push(r.edgeId);
160
+ const ext = { node: r.externalNode, pin: r.externalPin };
161
+ const mem = { node: r.memberNode, pin: r.memberPin };
162
+ connect.push(r.direction === 'in'
163
+ ? { id: mint.edge(), from: ext, to: mem }
164
+ : { id: mint.edge(), from: mem, to: ext });
165
+ }
166
+ return { disconnect, connect };
167
+ }
168
+ /** Partition edges relative to a member set — the heart of macro pin-proxying. An edge with exactly
169
+ * one endpoint inside the group crosses the boundary (input if it enters, output if it leaves); both
170
+ * inside is internal; both outside is ignored. Order within each bucket follows input order. */
171
+ export function boundaryEdges(members, edges) {
172
+ const inputs = [];
173
+ const outputs = [];
174
+ const internal = [];
175
+ for (const e of edges) {
176
+ const fromIn = members.has(e.from.node);
177
+ const toIn = members.has(e.to.node);
178
+ if (fromIn && toIn)
179
+ internal.push(e);
180
+ else if (toIn)
181
+ inputs.push(e);
182
+ else if (fromIn)
183
+ outputs.push(e);
184
+ }
185
+ return { inputs, outputs, internal };
186
+ }
187
+ /** Flatten collapsed macros into their primitives for a host interpreter: drop every `Macro` node and
188
+ * remap any edge endpoint that lands on a macro proxy pin back to the member pin it bridges (via the
189
+ * macro's `state.proxyMap`). Recurses through nested macros (a member pin may itself be an inner
190
+ * macro's proxy pin). Pure — never mutates the inputs. Internal member↔member edges pass through
191
+ * untouched; the macro grouping becomes purely visual. */
192
+ export function flattenMacroProxies(nodes, edges) {
193
+ const macroProxy = new Map();
194
+ for (const n of nodes) {
195
+ if (n.type !== MACRO_TYPE)
196
+ continue;
197
+ const m = new Map();
198
+ for (const r of (n.state['proxyMap'] ?? [])) {
199
+ m.set(String(r.macroPin), { node: r.memberNode, pin: r.memberPin });
200
+ }
201
+ macroProxy.set(String(n.id), m);
202
+ }
203
+ const flatten = (node, pin) => {
204
+ let n = node, p = pin, guard = 0;
205
+ while (guard++ < 64) {
206
+ const next = macroProxy.get(String(n))?.get(String(p));
207
+ if (!next)
208
+ break;
209
+ n = next.node;
210
+ p = next.pin;
211
+ }
212
+ return { node: n, pin: p };
213
+ };
214
+ const outNodes = nodes.filter((n) => n.type !== MACRO_TYPE);
215
+ const outEdges = [];
216
+ for (const e of edges) {
217
+ const from = flatten(e.from.node, e.from.pin);
218
+ const to = flatten(e.to.node, e.to.pin);
219
+ // An endpoint still on a macro means a missing proxy mapping — drop the dangling edge.
220
+ if (macroProxy.has(String(from.node)) || macroProxy.has(String(to.node)))
221
+ continue;
222
+ outEdges.push({ id: e.id, from, to });
223
+ }
224
+ return { nodes: outNodes, edges: outEdges };
225
+ }
226
+ //# sourceMappingURL=macro.js.map