@streetui/graph 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 StreetUI contributors
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,26 @@
1
+ # @streetui/graph
2
+
3
+ StreetUI Semantic Application Graph — nodes, relationships, traversal, validation
4
+
5
+ Part of [StreetUI](https://github.com/streetui/streetui) — a semantic,
6
+ signal-based UI framework with its own reactivity and keyed DOM reconciler
7
+ (no virtual DOM).
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @streetui/graph
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import * as pkg from '@streetui/graph';
19
+ ```
20
+
21
+ Both ESM (`import`) and CommonJS (`require`) entry points are shipped, with
22
+ matching TypeScript declarations.
23
+
24
+ ## License
25
+
26
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ApplicationGraph: () => ApplicationGraph,
24
+ GraphNode: () => GraphNode
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/graph-node.ts
29
+ var import_core = require("@streetui/core");
30
+ var GraphNode = class _GraphNode {
31
+ id;
32
+ type;
33
+ key;
34
+ props;
35
+ events;
36
+ stateRefs;
37
+ children;
38
+ parent;
39
+ constructor(type, options = {}) {
40
+ this.type = type;
41
+ this.id = options.id ?? (0, import_core.generateNodeId)(type);
42
+ this.key = options.key;
43
+ this.props = options.props ?? {};
44
+ this.events = options.events ?? [];
45
+ this.stateRefs = options.stateRefs ?? [];
46
+ this.children = [];
47
+ this.parent = null;
48
+ }
49
+ // ── Child management ────────────────────────────────────────────────────────
50
+ appendChild(child) {
51
+ if (child.parent !== null) {
52
+ child.parent.removeChild(child);
53
+ }
54
+ child.parent = this;
55
+ this.children.push(child);
56
+ }
57
+ insertBefore(child, reference) {
58
+ const idx = this.children.indexOf(reference);
59
+ if (idx === -1) {
60
+ this.appendChild(child);
61
+ return;
62
+ }
63
+ if (child.parent !== null) {
64
+ child.parent.removeChild(child);
65
+ }
66
+ child.parent = this;
67
+ this.children.splice(idx, 0, child);
68
+ }
69
+ removeChild(child) {
70
+ const idx = this.children.indexOf(child);
71
+ if (idx === -1) return;
72
+ this.children.splice(idx, 1);
73
+ child.parent = null;
74
+ }
75
+ replaceChild(newChild, oldChild) {
76
+ const idx = this.children.indexOf(oldChild);
77
+ if (idx === -1) {
78
+ throw new Error(`GraphNode.replaceChild: oldChild is not a child of this node`);
79
+ }
80
+ if (newChild.parent !== null) {
81
+ newChild.parent.removeChild(newChild);
82
+ }
83
+ oldChild.parent = null;
84
+ newChild.parent = this;
85
+ this.children.splice(idx, 1, newChild);
86
+ }
87
+ // ── Prop helpers ────────────────────────────────────────────────────────────
88
+ setProp(key, value) {
89
+ this.props = { ...this.props, [key]: value };
90
+ }
91
+ getProp(key) {
92
+ return this.props[key];
93
+ }
94
+ // ── Event helpers ───────────────────────────────────────────────────────────
95
+ addEvent(descriptor) {
96
+ this.events.push(descriptor);
97
+ }
98
+ removeEvent(type) {
99
+ this.events = this.events.filter((e) => e.type !== type);
100
+ }
101
+ // ── Queries ─────────────────────────────────────────────────────────────────
102
+ get isLeaf() {
103
+ return this.children.length === 0;
104
+ }
105
+ get depth() {
106
+ let d = 0;
107
+ let node = this.parent;
108
+ while (node !== null) {
109
+ d++;
110
+ node = node.parent;
111
+ }
112
+ return d;
113
+ }
114
+ get root() {
115
+ let node = this;
116
+ while (node.parent !== null) {
117
+ node = node.parent;
118
+ }
119
+ return node;
120
+ }
121
+ /** Shallow clone — does not clone children. */
122
+ shallowClone() {
123
+ const opts = {
124
+ props: { ...this.props },
125
+ events: [...this.events],
126
+ stateRefs: [...this.stateRefs]
127
+ };
128
+ if (this.key !== void 0) opts.key = this.key;
129
+ return new _GraphNode(this.type, opts);
130
+ }
131
+ };
132
+
133
+ // src/graph.ts
134
+ var import_core2 = require("@streetui/core");
135
+ var ApplicationGraph = class {
136
+ root;
137
+ name;
138
+ version;
139
+ _nodeIndex = /* @__PURE__ */ new Map();
140
+ /** Handler registry — maps handlerKey → actual function */
141
+ handlers = /* @__PURE__ */ new Map();
142
+ constructor(options) {
143
+ this.name = options.name;
144
+ this.version = options.version ?? "0.0.1";
145
+ this.root = new GraphNode("application", { props: { name: options.name } });
146
+ this._nodeIndex.set(this.root.id, this.root);
147
+ }
148
+ // ── Node creation & attachment ────────────────────────────────────────────
149
+ createNode(type, options = {}) {
150
+ const nodeOpts = {};
151
+ if (options.key !== void 0) nodeOpts.key = options.key;
152
+ if (options.props !== void 0) nodeOpts.props = options.props;
153
+ const node = new GraphNode(type, nodeOpts);
154
+ this._nodeIndex.set(node.id, node);
155
+ if (options.parent !== void 0) {
156
+ options.parent.appendChild(node);
157
+ }
158
+ return node;
159
+ }
160
+ attachNode(node, parent) {
161
+ this._nodeIndex.set(node.id, node);
162
+ parent.appendChild(node);
163
+ }
164
+ detachNode(node) {
165
+ if (node.parent !== null) {
166
+ node.parent.removeChild(node);
167
+ }
168
+ this._removeFromIndex(node);
169
+ }
170
+ _removeFromIndex(node) {
171
+ this._nodeIndex.delete(node.id);
172
+ this._unregisterNodeHandlers(node);
173
+ for (const child of node.children) {
174
+ this._removeFromIndex(child);
175
+ }
176
+ }
177
+ /**
178
+ * Remove every handler-registry entry owned by a single node. A node owns:
179
+ * - one entry per event descriptor (its `handlerKey`),
180
+ * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced
181
+ * by node id, so they are never shared between nodes), and
182
+ * - a `__listbuild__<id>` entry if it is a reactive-list.
183
+ * Called for every node in a detached subtree so removing list items (or
184
+ * discarding freshly-built-but-unadopted item subtrees) leaves no stale
185
+ * registrations behind.
186
+ */
187
+ _unregisterNodeHandlers(node) {
188
+ for (const event of node.events) {
189
+ this.handlers.delete(event.handlerKey);
190
+ }
191
+ for (const ref of node.stateRefs) {
192
+ this.handlers.delete(`__signal__${ref.signalId}`);
193
+ }
194
+ this.handlers.delete(`__listbuild__${node.id}`);
195
+ }
196
+ // ── Handler registry ──────────────────────────────────────────────────────
197
+ registerHandler(key, fn) {
198
+ this.handlers.set(key, fn);
199
+ }
200
+ getHandler(key) {
201
+ return this.handlers.get(key);
202
+ }
203
+ /** True if a handler is currently registered under `key`. Inspection helper. */
204
+ hasHandler(key) {
205
+ return this.handlers.has(key);
206
+ }
207
+ /** Number of currently-registered handlers. Inspection helper. */
208
+ get handlerCount() {
209
+ return this.handlers.size;
210
+ }
211
+ // ── Lookup ────────────────────────────────────────────────────────────────
212
+ findById(id) {
213
+ return this._nodeIndex.get(id);
214
+ }
215
+ findAll(predicate) {
216
+ const results = [];
217
+ this._walk(this.root, (node) => {
218
+ if (predicate(node)) results.push(node);
219
+ });
220
+ return results;
221
+ }
222
+ findByType(type) {
223
+ return this.findAll((n) => n.type === type);
224
+ }
225
+ // ── Traversal ─────────────────────────────────────────────────────────────
226
+ walk(visitor) {
227
+ this._walk(this.root, visitor, 0);
228
+ }
229
+ _walk(node, visitor, depth = 0) {
230
+ visitor(node, depth);
231
+ for (const child of node.children) {
232
+ this._walk(child, visitor, depth + 1);
233
+ }
234
+ }
235
+ get nodeCount() {
236
+ return this._nodeIndex.size;
237
+ }
238
+ // ── Validation ────────────────────────────────────────────────────────────
239
+ validate() {
240
+ const dc = new import_core2.DiagnosticCollector();
241
+ this.walk((node) => {
242
+ for (const event of node.events) {
243
+ if (!this.handlers.has(event.handlerKey)) {
244
+ dc.warn(
245
+ "GRAPH_MISSING_HANDLER",
246
+ `Node "${node.id}" references handler "${event.handlerKey}" which is not registered`,
247
+ { nodeId: node.id }
248
+ );
249
+ }
250
+ }
251
+ if (node.type === "page" && node.parent?.type !== "application") {
252
+ dc.error(
253
+ "GRAPH_PAGE_DEPTH",
254
+ `Page node "${node.id}" must be a direct child of the application root`,
255
+ { nodeId: node.id }
256
+ );
257
+ }
258
+ });
259
+ return dc;
260
+ }
261
+ // ── Serialization ─────────────────────────────────────────────────────────
262
+ serialize() {
263
+ return {
264
+ name: this.name,
265
+ version: this.version,
266
+ root: this._serializeNode(this.root)
267
+ };
268
+ }
269
+ _serializeNode(node) {
270
+ const result = {
271
+ id: node.id,
272
+ type: node.type,
273
+ key: node.key,
274
+ props: node.props,
275
+ events: node.events,
276
+ stateRefs: node.stateRefs,
277
+ children: node.children.map((c) => this._serializeNode(c))
278
+ };
279
+ return result;
280
+ }
281
+ };
282
+ // Annotate the CommonJS export names for ESM import in node:
283
+ 0 && (module.exports = {
284
+ ApplicationGraph,
285
+ GraphNode
286
+ });
287
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/graph-node.ts","../src/graph.ts"],"sourcesContent":["export * from './graph-node.js';\nexport * from './graph.js';\n","/**\n * Semantic Application Graph nodes.\n *\n * Every element in a StreetUI application is represented as a GraphNode.\n * Nodes form a tree: each has an optional parent and an ordered list of children.\n */\n\nimport { generateNodeId, type NodeId, type SemanticNodeType } from '@streetui/core';\n\n// ── Property values ───────────────────────────────────────────────────────────\n\nexport type PropValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | string[]\n | number[]\n | Record<string, unknown>;\n\nexport type Props = Record<string, PropValue>;\n\n// ── Event descriptors ─────────────────────────────────────────────────────────\n\nexport interface EventDescriptor {\n readonly type: string;\n /** Reference key into the application's handler registry. */\n readonly handlerKey: string;\n}\n\n// ── State references ──────────────────────────────────────────────────────────\n\nexport interface StateRef {\n /** ID of the signal/store this node's property is bound to. */\n readonly signalId: string;\n /** The prop key on this node that is bound. */\n readonly propKey: string;\n}\n\n// ── The core graph node ───────────────────────────────────────────────────────\n\nexport interface GraphNodeData {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly key: string | undefined;\n props: Props;\n events: EventDescriptor[];\n stateRefs: StateRef[];\n children: GraphNode[];\n parent: GraphNode | null;\n}\n\nexport class GraphNode implements GraphNodeData {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly key: string | undefined;\n props: Props;\n events: EventDescriptor[];\n stateRefs: StateRef[];\n children: GraphNode[];\n parent: GraphNode | null;\n\n constructor(\n type: SemanticNodeType,\n options: {\n id?: NodeId;\n key?: string;\n props?: Props;\n events?: EventDescriptor[];\n stateRefs?: StateRef[];\n } = {},\n ) {\n this.type = type;\n this.id = options.id ?? generateNodeId(type);\n this.key = options.key;\n this.props = options.props ?? {};\n this.events = options.events ?? [];\n this.stateRefs = options.stateRefs ?? [];\n this.children = [];\n this.parent = null;\n }\n\n // ── Child management ────────────────────────────────────────────────────────\n\n appendChild(child: GraphNode): void {\n if (child.parent !== null) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.children.push(child);\n }\n\n insertBefore(child: GraphNode, reference: GraphNode): void {\n const idx = this.children.indexOf(reference);\n if (idx === -1) {\n this.appendChild(child);\n return;\n }\n if (child.parent !== null) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.children.splice(idx, 0, child);\n }\n\n removeChild(child: GraphNode): void {\n const idx = this.children.indexOf(child);\n if (idx === -1) return;\n this.children.splice(idx, 1);\n child.parent = null;\n }\n\n replaceChild(newChild: GraphNode, oldChild: GraphNode): void {\n const idx = this.children.indexOf(oldChild);\n if (idx === -1) {\n throw new Error(`GraphNode.replaceChild: oldChild is not a child of this node`);\n }\n if (newChild.parent !== null) {\n newChild.parent.removeChild(newChild);\n }\n oldChild.parent = null;\n newChild.parent = this;\n this.children.splice(idx, 1, newChild);\n }\n\n // ── Prop helpers ────────────────────────────────────────────────────────────\n\n setProp(key: string, value: PropValue): void {\n this.props = { ...this.props, [key]: value };\n }\n\n getProp<T extends PropValue = PropValue>(key: string): T | undefined {\n return this.props[key] as T | undefined;\n }\n\n // ── Event helpers ───────────────────────────────────────────────────────────\n\n addEvent(descriptor: EventDescriptor): void {\n this.events.push(descriptor);\n }\n\n removeEvent(type: string): void {\n this.events = this.events.filter(e => e.type !== type);\n }\n\n // ── Queries ─────────────────────────────────────────────────────────────────\n\n get isLeaf(): boolean {\n return this.children.length === 0;\n }\n\n get depth(): number {\n let d = 0;\n let node: GraphNode | null = this.parent;\n while (node !== null) {\n d++;\n node = node.parent;\n }\n return d;\n }\n\n get root(): GraphNode {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let node: GraphNode = this;\n while (node.parent !== null) {\n node = node.parent;\n }\n return node;\n }\n\n /** Shallow clone — does not clone children. */\n shallowClone(): GraphNode {\n const opts: { key?: string; props: Props; events: EventDescriptor[]; stateRefs: StateRef[] } = {\n props: { ...this.props },\n events: [...this.events],\n stateRefs: [...this.stateRefs],\n };\n if (this.key !== undefined) opts.key = this.key;\n return new GraphNode(this.type, opts);\n }\n}\n","/**\n * The Semantic Application Graph.\n *\n * Holds the application root node and all its descendants.\n * Supports traversal, lookup by ID, validation, and serialization.\n */\n\nimport { type NodeId, DiagnosticCollector } from '@streetui/core';\nimport { GraphNode, type Props, type EventDescriptor } from './graph-node.js';\n\nexport interface ApplicationGraphOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport interface HandlerFn {\n (...args: unknown[]): unknown;\n}\n\nexport class ApplicationGraph {\n readonly root: GraphNode;\n readonly name: string;\n readonly version: string;\n private readonly _nodeIndex: Map<NodeId, GraphNode> = new Map();\n /** Handler registry — maps handlerKey → actual function */\n readonly handlers: Map<string, HandlerFn> = new Map();\n\n constructor(options: ApplicationGraphOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.root = new GraphNode('application', { props: { name: options.name } });\n this._nodeIndex.set(this.root.id, this.root);\n }\n\n // ── Node creation & attachment ────────────────────────────────────────────\n\n createNode(\n type: GraphNode['type'],\n options: { key?: string; props?: Props; parent?: GraphNode } = {},\n ): GraphNode {\n const nodeOpts: { key?: string; props?: Props } = {};\n if (options.key !== undefined) nodeOpts.key = options.key;\n if (options.props !== undefined) nodeOpts.props = options.props;\n const node = new GraphNode(type, nodeOpts);\n this._nodeIndex.set(node.id, node);\n if (options.parent !== undefined) {\n options.parent.appendChild(node);\n }\n return node;\n }\n\n attachNode(node: GraphNode, parent: GraphNode): void {\n this._nodeIndex.set(node.id, node);\n parent.appendChild(node);\n }\n\n detachNode(node: GraphNode): void {\n if (node.parent !== null) {\n node.parent.removeChild(node);\n }\n this._removeFromIndex(node);\n }\n\n private _removeFromIndex(node: GraphNode): void {\n this._nodeIndex.delete(node.id);\n this._unregisterNodeHandlers(node);\n for (const child of node.children) {\n this._removeFromIndex(child);\n }\n }\n\n /**\n * Remove every handler-registry entry owned by a single node. A node owns:\n * - one entry per event descriptor (its `handlerKey`),\n * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced\n * by node id, so they are never shared between nodes), and\n * - a `__listbuild__<id>` entry if it is a reactive-list.\n * Called for every node in a detached subtree so removing list items (or\n * discarding freshly-built-but-unadopted item subtrees) leaves no stale\n * registrations behind.\n */\n private _unregisterNodeHandlers(node: GraphNode): void {\n for (const event of node.events) {\n this.handlers.delete(event.handlerKey);\n }\n for (const ref of node.stateRefs) {\n this.handlers.delete(`__signal__${ref.signalId}`);\n }\n this.handlers.delete(`__listbuild__${node.id}`);\n }\n\n // ── Handler registry ──────────────────────────────────────────────────────\n\n registerHandler(key: string, fn: HandlerFn): void {\n this.handlers.set(key, fn);\n }\n\n getHandler(key: string): HandlerFn | undefined {\n return this.handlers.get(key);\n }\n\n /** True if a handler is currently registered under `key`. Inspection helper. */\n hasHandler(key: string): boolean {\n return this.handlers.has(key);\n }\n\n /** Number of currently-registered handlers. Inspection helper. */\n get handlerCount(): number {\n return this.handlers.size;\n }\n\n // ── Lookup ────────────────────────────────────────────────────────────────\n\n findById(id: NodeId): GraphNode | undefined {\n return this._nodeIndex.get(id);\n }\n\n findAll(predicate: (node: GraphNode) => boolean): GraphNode[] {\n const results: GraphNode[] = [];\n this._walk(this.root, node => {\n if (predicate(node)) results.push(node);\n });\n return results;\n }\n\n findByType(type: GraphNode['type']): GraphNode[] {\n return this.findAll(n => n.type === type);\n }\n\n // ── Traversal ─────────────────────────────────────────────────────────────\n\n walk(visitor: (node: GraphNode, depth: number) => void): void {\n this._walk(this.root, visitor, 0);\n }\n\n private _walk(\n node: GraphNode,\n visitor: (node: GraphNode, depth: number) => void,\n depth: number = 0,\n ): void {\n visitor(node, depth);\n for (const child of node.children) {\n this._walk(child, visitor, depth + 1);\n }\n }\n\n get nodeCount(): number {\n return this._nodeIndex.size;\n }\n\n // ── Validation ────────────────────────────────────────────────────────────\n\n validate(): DiagnosticCollector {\n const dc = new DiagnosticCollector();\n\n this.walk((node) => {\n // Validate event handler references exist\n for (const event of node.events) {\n if (!this.handlers.has(event.handlerKey)) {\n dc.warn(\n 'GRAPH_MISSING_HANDLER',\n `Node \"${node.id}\" references handler \"${event.handlerKey}\" which is not registered`,\n { nodeId: node.id },\n );\n }\n }\n\n // Validate page nodes are direct children of root\n if (node.type === 'page' && node.parent?.type !== 'application') {\n dc.error(\n 'GRAPH_PAGE_DEPTH',\n `Page node \"${node.id}\" must be a direct child of the application root`,\n { nodeId: node.id },\n );\n }\n });\n\n return dc;\n }\n\n // ── Serialization ─────────────────────────────────────────────────────────\n\n serialize(): SerializedGraph {\n return {\n name: this.name,\n version: this.version,\n root: this._serializeNode(this.root),\n };\n }\n\n private _serializeNode(node: GraphNode): SerializedNode {\n const result: SerializedNode = {\n id: node.id,\n type: node.type,\n key: node.key,\n props: node.props,\n events: node.events,\n stateRefs: node.stateRefs,\n children: node.children.map(c => this._serializeNode(c)),\n };\n return result;\n }\n}\n\nexport interface SerializedNode {\n readonly id: string;\n readonly type: string;\n readonly key: string | undefined;\n readonly props: Props;\n readonly events: EventDescriptor[];\n readonly stateRefs: unknown[];\n readonly children: SerializedNode[];\n}\n\nexport interface SerializedGraph {\n readonly name: string;\n readonly version: string;\n readonly root: SerializedNode;\n}\n"],"mappings":"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","names":["import_core"]}
@@ -0,0 +1,136 @@
1
+ import { NodeId, SemanticNodeType, DiagnosticCollector } from '@streetui/core';
2
+
3
+ /**
4
+ * Semantic Application Graph nodes.
5
+ *
6
+ * Every element in a StreetUI application is represented as a GraphNode.
7
+ * Nodes form a tree: each has an optional parent and an ordered list of children.
8
+ */
9
+
10
+ type PropValue = string | number | boolean | null | undefined | string[] | number[] | Record<string, unknown>;
11
+ type Props = Record<string, PropValue>;
12
+ interface EventDescriptor {
13
+ readonly type: string;
14
+ /** Reference key into the application's handler registry. */
15
+ readonly handlerKey: string;
16
+ }
17
+ interface StateRef {
18
+ /** ID of the signal/store this node's property is bound to. */
19
+ readonly signalId: string;
20
+ /** The prop key on this node that is bound. */
21
+ readonly propKey: string;
22
+ }
23
+ interface GraphNodeData {
24
+ readonly id: NodeId;
25
+ readonly type: SemanticNodeType;
26
+ readonly key: string | undefined;
27
+ props: Props;
28
+ events: EventDescriptor[];
29
+ stateRefs: StateRef[];
30
+ children: GraphNode[];
31
+ parent: GraphNode | null;
32
+ }
33
+ declare class GraphNode implements GraphNodeData {
34
+ readonly id: NodeId;
35
+ readonly type: SemanticNodeType;
36
+ readonly key: string | undefined;
37
+ props: Props;
38
+ events: EventDescriptor[];
39
+ stateRefs: StateRef[];
40
+ children: GraphNode[];
41
+ parent: GraphNode | null;
42
+ constructor(type: SemanticNodeType, options?: {
43
+ id?: NodeId;
44
+ key?: string;
45
+ props?: Props;
46
+ events?: EventDescriptor[];
47
+ stateRefs?: StateRef[];
48
+ });
49
+ appendChild(child: GraphNode): void;
50
+ insertBefore(child: GraphNode, reference: GraphNode): void;
51
+ removeChild(child: GraphNode): void;
52
+ replaceChild(newChild: GraphNode, oldChild: GraphNode): void;
53
+ setProp(key: string, value: PropValue): void;
54
+ getProp<T extends PropValue = PropValue>(key: string): T | undefined;
55
+ addEvent(descriptor: EventDescriptor): void;
56
+ removeEvent(type: string): void;
57
+ get isLeaf(): boolean;
58
+ get depth(): number;
59
+ get root(): GraphNode;
60
+ /** Shallow clone — does not clone children. */
61
+ shallowClone(): GraphNode;
62
+ }
63
+
64
+ /**
65
+ * The Semantic Application Graph.
66
+ *
67
+ * Holds the application root node and all its descendants.
68
+ * Supports traversal, lookup by ID, validation, and serialization.
69
+ */
70
+
71
+ interface ApplicationGraphOptions {
72
+ readonly name: string;
73
+ readonly version?: string;
74
+ }
75
+ interface HandlerFn {
76
+ (...args: unknown[]): unknown;
77
+ }
78
+ declare class ApplicationGraph {
79
+ readonly root: GraphNode;
80
+ readonly name: string;
81
+ readonly version: string;
82
+ private readonly _nodeIndex;
83
+ /** Handler registry — maps handlerKey → actual function */
84
+ readonly handlers: Map<string, HandlerFn>;
85
+ constructor(options: ApplicationGraphOptions);
86
+ createNode(type: GraphNode['type'], options?: {
87
+ key?: string;
88
+ props?: Props;
89
+ parent?: GraphNode;
90
+ }): GraphNode;
91
+ attachNode(node: GraphNode, parent: GraphNode): void;
92
+ detachNode(node: GraphNode): void;
93
+ private _removeFromIndex;
94
+ /**
95
+ * Remove every handler-registry entry owned by a single node. A node owns:
96
+ * - one entry per event descriptor (its `handlerKey`),
97
+ * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced
98
+ * by node id, so they are never shared between nodes), and
99
+ * - a `__listbuild__<id>` entry if it is a reactive-list.
100
+ * Called for every node in a detached subtree so removing list items (or
101
+ * discarding freshly-built-but-unadopted item subtrees) leaves no stale
102
+ * registrations behind.
103
+ */
104
+ private _unregisterNodeHandlers;
105
+ registerHandler(key: string, fn: HandlerFn): void;
106
+ getHandler(key: string): HandlerFn | undefined;
107
+ /** True if a handler is currently registered under `key`. Inspection helper. */
108
+ hasHandler(key: string): boolean;
109
+ /** Number of currently-registered handlers. Inspection helper. */
110
+ get handlerCount(): number;
111
+ findById(id: NodeId): GraphNode | undefined;
112
+ findAll(predicate: (node: GraphNode) => boolean): GraphNode[];
113
+ findByType(type: GraphNode['type']): GraphNode[];
114
+ walk(visitor: (node: GraphNode, depth: number) => void): void;
115
+ private _walk;
116
+ get nodeCount(): number;
117
+ validate(): DiagnosticCollector;
118
+ serialize(): SerializedGraph;
119
+ private _serializeNode;
120
+ }
121
+ interface SerializedNode {
122
+ readonly id: string;
123
+ readonly type: string;
124
+ readonly key: string | undefined;
125
+ readonly props: Props;
126
+ readonly events: EventDescriptor[];
127
+ readonly stateRefs: unknown[];
128
+ readonly children: SerializedNode[];
129
+ }
130
+ interface SerializedGraph {
131
+ readonly name: string;
132
+ readonly version: string;
133
+ readonly root: SerializedNode;
134
+ }
135
+
136
+ export { ApplicationGraph, type ApplicationGraphOptions, type EventDescriptor, GraphNode, type GraphNodeData, type HandlerFn, type PropValue, type Props, type SerializedGraph, type SerializedNode, type StateRef };
@@ -0,0 +1,136 @@
1
+ import { NodeId, SemanticNodeType, DiagnosticCollector } from '@streetui/core';
2
+
3
+ /**
4
+ * Semantic Application Graph nodes.
5
+ *
6
+ * Every element in a StreetUI application is represented as a GraphNode.
7
+ * Nodes form a tree: each has an optional parent and an ordered list of children.
8
+ */
9
+
10
+ type PropValue = string | number | boolean | null | undefined | string[] | number[] | Record<string, unknown>;
11
+ type Props = Record<string, PropValue>;
12
+ interface EventDescriptor {
13
+ readonly type: string;
14
+ /** Reference key into the application's handler registry. */
15
+ readonly handlerKey: string;
16
+ }
17
+ interface StateRef {
18
+ /** ID of the signal/store this node's property is bound to. */
19
+ readonly signalId: string;
20
+ /** The prop key on this node that is bound. */
21
+ readonly propKey: string;
22
+ }
23
+ interface GraphNodeData {
24
+ readonly id: NodeId;
25
+ readonly type: SemanticNodeType;
26
+ readonly key: string | undefined;
27
+ props: Props;
28
+ events: EventDescriptor[];
29
+ stateRefs: StateRef[];
30
+ children: GraphNode[];
31
+ parent: GraphNode | null;
32
+ }
33
+ declare class GraphNode implements GraphNodeData {
34
+ readonly id: NodeId;
35
+ readonly type: SemanticNodeType;
36
+ readonly key: string | undefined;
37
+ props: Props;
38
+ events: EventDescriptor[];
39
+ stateRefs: StateRef[];
40
+ children: GraphNode[];
41
+ parent: GraphNode | null;
42
+ constructor(type: SemanticNodeType, options?: {
43
+ id?: NodeId;
44
+ key?: string;
45
+ props?: Props;
46
+ events?: EventDescriptor[];
47
+ stateRefs?: StateRef[];
48
+ });
49
+ appendChild(child: GraphNode): void;
50
+ insertBefore(child: GraphNode, reference: GraphNode): void;
51
+ removeChild(child: GraphNode): void;
52
+ replaceChild(newChild: GraphNode, oldChild: GraphNode): void;
53
+ setProp(key: string, value: PropValue): void;
54
+ getProp<T extends PropValue = PropValue>(key: string): T | undefined;
55
+ addEvent(descriptor: EventDescriptor): void;
56
+ removeEvent(type: string): void;
57
+ get isLeaf(): boolean;
58
+ get depth(): number;
59
+ get root(): GraphNode;
60
+ /** Shallow clone — does not clone children. */
61
+ shallowClone(): GraphNode;
62
+ }
63
+
64
+ /**
65
+ * The Semantic Application Graph.
66
+ *
67
+ * Holds the application root node and all its descendants.
68
+ * Supports traversal, lookup by ID, validation, and serialization.
69
+ */
70
+
71
+ interface ApplicationGraphOptions {
72
+ readonly name: string;
73
+ readonly version?: string;
74
+ }
75
+ interface HandlerFn {
76
+ (...args: unknown[]): unknown;
77
+ }
78
+ declare class ApplicationGraph {
79
+ readonly root: GraphNode;
80
+ readonly name: string;
81
+ readonly version: string;
82
+ private readonly _nodeIndex;
83
+ /** Handler registry — maps handlerKey → actual function */
84
+ readonly handlers: Map<string, HandlerFn>;
85
+ constructor(options: ApplicationGraphOptions);
86
+ createNode(type: GraphNode['type'], options?: {
87
+ key?: string;
88
+ props?: Props;
89
+ parent?: GraphNode;
90
+ }): GraphNode;
91
+ attachNode(node: GraphNode, parent: GraphNode): void;
92
+ detachNode(node: GraphNode): void;
93
+ private _removeFromIndex;
94
+ /**
95
+ * Remove every handler-registry entry owned by a single node. A node owns:
96
+ * - one entry per event descriptor (its `handlerKey`),
97
+ * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced
98
+ * by node id, so they are never shared between nodes), and
99
+ * - a `__listbuild__<id>` entry if it is a reactive-list.
100
+ * Called for every node in a detached subtree so removing list items (or
101
+ * discarding freshly-built-but-unadopted item subtrees) leaves no stale
102
+ * registrations behind.
103
+ */
104
+ private _unregisterNodeHandlers;
105
+ registerHandler(key: string, fn: HandlerFn): void;
106
+ getHandler(key: string): HandlerFn | undefined;
107
+ /** True if a handler is currently registered under `key`. Inspection helper. */
108
+ hasHandler(key: string): boolean;
109
+ /** Number of currently-registered handlers. Inspection helper. */
110
+ get handlerCount(): number;
111
+ findById(id: NodeId): GraphNode | undefined;
112
+ findAll(predicate: (node: GraphNode) => boolean): GraphNode[];
113
+ findByType(type: GraphNode['type']): GraphNode[];
114
+ walk(visitor: (node: GraphNode, depth: number) => void): void;
115
+ private _walk;
116
+ get nodeCount(): number;
117
+ validate(): DiagnosticCollector;
118
+ serialize(): SerializedGraph;
119
+ private _serializeNode;
120
+ }
121
+ interface SerializedNode {
122
+ readonly id: string;
123
+ readonly type: string;
124
+ readonly key: string | undefined;
125
+ readonly props: Props;
126
+ readonly events: EventDescriptor[];
127
+ readonly stateRefs: unknown[];
128
+ readonly children: SerializedNode[];
129
+ }
130
+ interface SerializedGraph {
131
+ readonly name: string;
132
+ readonly version: string;
133
+ readonly root: SerializedNode;
134
+ }
135
+
136
+ export { ApplicationGraph, type ApplicationGraphOptions, type EventDescriptor, GraphNode, type GraphNodeData, type HandlerFn, type PropValue, type Props, type SerializedGraph, type SerializedNode, type StateRef };
package/dist/index.js ADDED
@@ -0,0 +1,259 @@
1
+ // src/graph-node.ts
2
+ import { generateNodeId } from "@streetui/core";
3
+ var GraphNode = class _GraphNode {
4
+ id;
5
+ type;
6
+ key;
7
+ props;
8
+ events;
9
+ stateRefs;
10
+ children;
11
+ parent;
12
+ constructor(type, options = {}) {
13
+ this.type = type;
14
+ this.id = options.id ?? generateNodeId(type);
15
+ this.key = options.key;
16
+ this.props = options.props ?? {};
17
+ this.events = options.events ?? [];
18
+ this.stateRefs = options.stateRefs ?? [];
19
+ this.children = [];
20
+ this.parent = null;
21
+ }
22
+ // ── Child management ────────────────────────────────────────────────────────
23
+ appendChild(child) {
24
+ if (child.parent !== null) {
25
+ child.parent.removeChild(child);
26
+ }
27
+ child.parent = this;
28
+ this.children.push(child);
29
+ }
30
+ insertBefore(child, reference) {
31
+ const idx = this.children.indexOf(reference);
32
+ if (idx === -1) {
33
+ this.appendChild(child);
34
+ return;
35
+ }
36
+ if (child.parent !== null) {
37
+ child.parent.removeChild(child);
38
+ }
39
+ child.parent = this;
40
+ this.children.splice(idx, 0, child);
41
+ }
42
+ removeChild(child) {
43
+ const idx = this.children.indexOf(child);
44
+ if (idx === -1) return;
45
+ this.children.splice(idx, 1);
46
+ child.parent = null;
47
+ }
48
+ replaceChild(newChild, oldChild) {
49
+ const idx = this.children.indexOf(oldChild);
50
+ if (idx === -1) {
51
+ throw new Error(`GraphNode.replaceChild: oldChild is not a child of this node`);
52
+ }
53
+ if (newChild.parent !== null) {
54
+ newChild.parent.removeChild(newChild);
55
+ }
56
+ oldChild.parent = null;
57
+ newChild.parent = this;
58
+ this.children.splice(idx, 1, newChild);
59
+ }
60
+ // ── Prop helpers ────────────────────────────────────────────────────────────
61
+ setProp(key, value) {
62
+ this.props = { ...this.props, [key]: value };
63
+ }
64
+ getProp(key) {
65
+ return this.props[key];
66
+ }
67
+ // ── Event helpers ───────────────────────────────────────────────────────────
68
+ addEvent(descriptor) {
69
+ this.events.push(descriptor);
70
+ }
71
+ removeEvent(type) {
72
+ this.events = this.events.filter((e) => e.type !== type);
73
+ }
74
+ // ── Queries ─────────────────────────────────────────────────────────────────
75
+ get isLeaf() {
76
+ return this.children.length === 0;
77
+ }
78
+ get depth() {
79
+ let d = 0;
80
+ let node = this.parent;
81
+ while (node !== null) {
82
+ d++;
83
+ node = node.parent;
84
+ }
85
+ return d;
86
+ }
87
+ get root() {
88
+ let node = this;
89
+ while (node.parent !== null) {
90
+ node = node.parent;
91
+ }
92
+ return node;
93
+ }
94
+ /** Shallow clone — does not clone children. */
95
+ shallowClone() {
96
+ const opts = {
97
+ props: { ...this.props },
98
+ events: [...this.events],
99
+ stateRefs: [...this.stateRefs]
100
+ };
101
+ if (this.key !== void 0) opts.key = this.key;
102
+ return new _GraphNode(this.type, opts);
103
+ }
104
+ };
105
+
106
+ // src/graph.ts
107
+ import { DiagnosticCollector } from "@streetui/core";
108
+ var ApplicationGraph = class {
109
+ root;
110
+ name;
111
+ version;
112
+ _nodeIndex = /* @__PURE__ */ new Map();
113
+ /** Handler registry — maps handlerKey → actual function */
114
+ handlers = /* @__PURE__ */ new Map();
115
+ constructor(options) {
116
+ this.name = options.name;
117
+ this.version = options.version ?? "0.0.1";
118
+ this.root = new GraphNode("application", { props: { name: options.name } });
119
+ this._nodeIndex.set(this.root.id, this.root);
120
+ }
121
+ // ── Node creation & attachment ────────────────────────────────────────────
122
+ createNode(type, options = {}) {
123
+ const nodeOpts = {};
124
+ if (options.key !== void 0) nodeOpts.key = options.key;
125
+ if (options.props !== void 0) nodeOpts.props = options.props;
126
+ const node = new GraphNode(type, nodeOpts);
127
+ this._nodeIndex.set(node.id, node);
128
+ if (options.parent !== void 0) {
129
+ options.parent.appendChild(node);
130
+ }
131
+ return node;
132
+ }
133
+ attachNode(node, parent) {
134
+ this._nodeIndex.set(node.id, node);
135
+ parent.appendChild(node);
136
+ }
137
+ detachNode(node) {
138
+ if (node.parent !== null) {
139
+ node.parent.removeChild(node);
140
+ }
141
+ this._removeFromIndex(node);
142
+ }
143
+ _removeFromIndex(node) {
144
+ this._nodeIndex.delete(node.id);
145
+ this._unregisterNodeHandlers(node);
146
+ for (const child of node.children) {
147
+ this._removeFromIndex(child);
148
+ }
149
+ }
150
+ /**
151
+ * Remove every handler-registry entry owned by a single node. A node owns:
152
+ * - one entry per event descriptor (its `handlerKey`),
153
+ * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced
154
+ * by node id, so they are never shared between nodes), and
155
+ * - a `__listbuild__<id>` entry if it is a reactive-list.
156
+ * Called for every node in a detached subtree so removing list items (or
157
+ * discarding freshly-built-but-unadopted item subtrees) leaves no stale
158
+ * registrations behind.
159
+ */
160
+ _unregisterNodeHandlers(node) {
161
+ for (const event of node.events) {
162
+ this.handlers.delete(event.handlerKey);
163
+ }
164
+ for (const ref of node.stateRefs) {
165
+ this.handlers.delete(`__signal__${ref.signalId}`);
166
+ }
167
+ this.handlers.delete(`__listbuild__${node.id}`);
168
+ }
169
+ // ── Handler registry ──────────────────────────────────────────────────────
170
+ registerHandler(key, fn) {
171
+ this.handlers.set(key, fn);
172
+ }
173
+ getHandler(key) {
174
+ return this.handlers.get(key);
175
+ }
176
+ /** True if a handler is currently registered under `key`. Inspection helper. */
177
+ hasHandler(key) {
178
+ return this.handlers.has(key);
179
+ }
180
+ /** Number of currently-registered handlers. Inspection helper. */
181
+ get handlerCount() {
182
+ return this.handlers.size;
183
+ }
184
+ // ── Lookup ────────────────────────────────────────────────────────────────
185
+ findById(id) {
186
+ return this._nodeIndex.get(id);
187
+ }
188
+ findAll(predicate) {
189
+ const results = [];
190
+ this._walk(this.root, (node) => {
191
+ if (predicate(node)) results.push(node);
192
+ });
193
+ return results;
194
+ }
195
+ findByType(type) {
196
+ return this.findAll((n) => n.type === type);
197
+ }
198
+ // ── Traversal ─────────────────────────────────────────────────────────────
199
+ walk(visitor) {
200
+ this._walk(this.root, visitor, 0);
201
+ }
202
+ _walk(node, visitor, depth = 0) {
203
+ visitor(node, depth);
204
+ for (const child of node.children) {
205
+ this._walk(child, visitor, depth + 1);
206
+ }
207
+ }
208
+ get nodeCount() {
209
+ return this._nodeIndex.size;
210
+ }
211
+ // ── Validation ────────────────────────────────────────────────────────────
212
+ validate() {
213
+ const dc = new DiagnosticCollector();
214
+ this.walk((node) => {
215
+ for (const event of node.events) {
216
+ if (!this.handlers.has(event.handlerKey)) {
217
+ dc.warn(
218
+ "GRAPH_MISSING_HANDLER",
219
+ `Node "${node.id}" references handler "${event.handlerKey}" which is not registered`,
220
+ { nodeId: node.id }
221
+ );
222
+ }
223
+ }
224
+ if (node.type === "page" && node.parent?.type !== "application") {
225
+ dc.error(
226
+ "GRAPH_PAGE_DEPTH",
227
+ `Page node "${node.id}" must be a direct child of the application root`,
228
+ { nodeId: node.id }
229
+ );
230
+ }
231
+ });
232
+ return dc;
233
+ }
234
+ // ── Serialization ─────────────────────────────────────────────────────────
235
+ serialize() {
236
+ return {
237
+ name: this.name,
238
+ version: this.version,
239
+ root: this._serializeNode(this.root)
240
+ };
241
+ }
242
+ _serializeNode(node) {
243
+ const result = {
244
+ id: node.id,
245
+ type: node.type,
246
+ key: node.key,
247
+ props: node.props,
248
+ events: node.events,
249
+ stateRefs: node.stateRefs,
250
+ children: node.children.map((c) => this._serializeNode(c))
251
+ };
252
+ return result;
253
+ }
254
+ };
255
+ export {
256
+ ApplicationGraph,
257
+ GraphNode
258
+ };
259
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graph-node.ts","../src/graph.ts"],"sourcesContent":["/**\n * Semantic Application Graph nodes.\n *\n * Every element in a StreetUI application is represented as a GraphNode.\n * Nodes form a tree: each has an optional parent and an ordered list of children.\n */\n\nimport { generateNodeId, type NodeId, type SemanticNodeType } from '@streetui/core';\n\n// ── Property values ───────────────────────────────────────────────────────────\n\nexport type PropValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | string[]\n | number[]\n | Record<string, unknown>;\n\nexport type Props = Record<string, PropValue>;\n\n// ── Event descriptors ─────────────────────────────────────────────────────────\n\nexport interface EventDescriptor {\n readonly type: string;\n /** Reference key into the application's handler registry. */\n readonly handlerKey: string;\n}\n\n// ── State references ──────────────────────────────────────────────────────────\n\nexport interface StateRef {\n /** ID of the signal/store this node's property is bound to. */\n readonly signalId: string;\n /** The prop key on this node that is bound. */\n readonly propKey: string;\n}\n\n// ── The core graph node ───────────────────────────────────────────────────────\n\nexport interface GraphNodeData {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly key: string | undefined;\n props: Props;\n events: EventDescriptor[];\n stateRefs: StateRef[];\n children: GraphNode[];\n parent: GraphNode | null;\n}\n\nexport class GraphNode implements GraphNodeData {\n readonly id: NodeId;\n readonly type: SemanticNodeType;\n readonly key: string | undefined;\n props: Props;\n events: EventDescriptor[];\n stateRefs: StateRef[];\n children: GraphNode[];\n parent: GraphNode | null;\n\n constructor(\n type: SemanticNodeType,\n options: {\n id?: NodeId;\n key?: string;\n props?: Props;\n events?: EventDescriptor[];\n stateRefs?: StateRef[];\n } = {},\n ) {\n this.type = type;\n this.id = options.id ?? generateNodeId(type);\n this.key = options.key;\n this.props = options.props ?? {};\n this.events = options.events ?? [];\n this.stateRefs = options.stateRefs ?? [];\n this.children = [];\n this.parent = null;\n }\n\n // ── Child management ────────────────────────────────────────────────────────\n\n appendChild(child: GraphNode): void {\n if (child.parent !== null) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.children.push(child);\n }\n\n insertBefore(child: GraphNode, reference: GraphNode): void {\n const idx = this.children.indexOf(reference);\n if (idx === -1) {\n this.appendChild(child);\n return;\n }\n if (child.parent !== null) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.children.splice(idx, 0, child);\n }\n\n removeChild(child: GraphNode): void {\n const idx = this.children.indexOf(child);\n if (idx === -1) return;\n this.children.splice(idx, 1);\n child.parent = null;\n }\n\n replaceChild(newChild: GraphNode, oldChild: GraphNode): void {\n const idx = this.children.indexOf(oldChild);\n if (idx === -1) {\n throw new Error(`GraphNode.replaceChild: oldChild is not a child of this node`);\n }\n if (newChild.parent !== null) {\n newChild.parent.removeChild(newChild);\n }\n oldChild.parent = null;\n newChild.parent = this;\n this.children.splice(idx, 1, newChild);\n }\n\n // ── Prop helpers ────────────────────────────────────────────────────────────\n\n setProp(key: string, value: PropValue): void {\n this.props = { ...this.props, [key]: value };\n }\n\n getProp<T extends PropValue = PropValue>(key: string): T | undefined {\n return this.props[key] as T | undefined;\n }\n\n // ── Event helpers ───────────────────────────────────────────────────────────\n\n addEvent(descriptor: EventDescriptor): void {\n this.events.push(descriptor);\n }\n\n removeEvent(type: string): void {\n this.events = this.events.filter(e => e.type !== type);\n }\n\n // ── Queries ─────────────────────────────────────────────────────────────────\n\n get isLeaf(): boolean {\n return this.children.length === 0;\n }\n\n get depth(): number {\n let d = 0;\n let node: GraphNode | null = this.parent;\n while (node !== null) {\n d++;\n node = node.parent;\n }\n return d;\n }\n\n get root(): GraphNode {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let node: GraphNode = this;\n while (node.parent !== null) {\n node = node.parent;\n }\n return node;\n }\n\n /** Shallow clone — does not clone children. */\n shallowClone(): GraphNode {\n const opts: { key?: string; props: Props; events: EventDescriptor[]; stateRefs: StateRef[] } = {\n props: { ...this.props },\n events: [...this.events],\n stateRefs: [...this.stateRefs],\n };\n if (this.key !== undefined) opts.key = this.key;\n return new GraphNode(this.type, opts);\n }\n}\n","/**\n * The Semantic Application Graph.\n *\n * Holds the application root node and all its descendants.\n * Supports traversal, lookup by ID, validation, and serialization.\n */\n\nimport { type NodeId, DiagnosticCollector } from '@streetui/core';\nimport { GraphNode, type Props, type EventDescriptor } from './graph-node.js';\n\nexport interface ApplicationGraphOptions {\n readonly name: string;\n readonly version?: string;\n}\n\nexport interface HandlerFn {\n (...args: unknown[]): unknown;\n}\n\nexport class ApplicationGraph {\n readonly root: GraphNode;\n readonly name: string;\n readonly version: string;\n private readonly _nodeIndex: Map<NodeId, GraphNode> = new Map();\n /** Handler registry — maps handlerKey → actual function */\n readonly handlers: Map<string, HandlerFn> = new Map();\n\n constructor(options: ApplicationGraphOptions) {\n this.name = options.name;\n this.version = options.version ?? '0.0.1';\n this.root = new GraphNode('application', { props: { name: options.name } });\n this._nodeIndex.set(this.root.id, this.root);\n }\n\n // ── Node creation & attachment ────────────────────────────────────────────\n\n createNode(\n type: GraphNode['type'],\n options: { key?: string; props?: Props; parent?: GraphNode } = {},\n ): GraphNode {\n const nodeOpts: { key?: string; props?: Props } = {};\n if (options.key !== undefined) nodeOpts.key = options.key;\n if (options.props !== undefined) nodeOpts.props = options.props;\n const node = new GraphNode(type, nodeOpts);\n this._nodeIndex.set(node.id, node);\n if (options.parent !== undefined) {\n options.parent.appendChild(node);\n }\n return node;\n }\n\n attachNode(node: GraphNode, parent: GraphNode): void {\n this._nodeIndex.set(node.id, node);\n parent.appendChild(node);\n }\n\n detachNode(node: GraphNode): void {\n if (node.parent !== null) {\n node.parent.removeChild(node);\n }\n this._removeFromIndex(node);\n }\n\n private _removeFromIndex(node: GraphNode): void {\n this._nodeIndex.delete(node.id);\n this._unregisterNodeHandlers(node);\n for (const child of node.children) {\n this._removeFromIndex(child);\n }\n }\n\n /**\n * Remove every handler-registry entry owned by a single node. A node owns:\n * - one entry per event descriptor (its `handlerKey`),\n * - one `__signal__<signalId>` entry per state ref (signalIds are namespaced\n * by node id, so they are never shared between nodes), and\n * - a `__listbuild__<id>` entry if it is a reactive-list.\n * Called for every node in a detached subtree so removing list items (or\n * discarding freshly-built-but-unadopted item subtrees) leaves no stale\n * registrations behind.\n */\n private _unregisterNodeHandlers(node: GraphNode): void {\n for (const event of node.events) {\n this.handlers.delete(event.handlerKey);\n }\n for (const ref of node.stateRefs) {\n this.handlers.delete(`__signal__${ref.signalId}`);\n }\n this.handlers.delete(`__listbuild__${node.id}`);\n }\n\n // ── Handler registry ──────────────────────────────────────────────────────\n\n registerHandler(key: string, fn: HandlerFn): void {\n this.handlers.set(key, fn);\n }\n\n getHandler(key: string): HandlerFn | undefined {\n return this.handlers.get(key);\n }\n\n /** True if a handler is currently registered under `key`. Inspection helper. */\n hasHandler(key: string): boolean {\n return this.handlers.has(key);\n }\n\n /** Number of currently-registered handlers. Inspection helper. */\n get handlerCount(): number {\n return this.handlers.size;\n }\n\n // ── Lookup ────────────────────────────────────────────────────────────────\n\n findById(id: NodeId): GraphNode | undefined {\n return this._nodeIndex.get(id);\n }\n\n findAll(predicate: (node: GraphNode) => boolean): GraphNode[] {\n const results: GraphNode[] = [];\n this._walk(this.root, node => {\n if (predicate(node)) results.push(node);\n });\n return results;\n }\n\n findByType(type: GraphNode['type']): GraphNode[] {\n return this.findAll(n => n.type === type);\n }\n\n // ── Traversal ─────────────────────────────────────────────────────────────\n\n walk(visitor: (node: GraphNode, depth: number) => void): void {\n this._walk(this.root, visitor, 0);\n }\n\n private _walk(\n node: GraphNode,\n visitor: (node: GraphNode, depth: number) => void,\n depth: number = 0,\n ): void {\n visitor(node, depth);\n for (const child of node.children) {\n this._walk(child, visitor, depth + 1);\n }\n }\n\n get nodeCount(): number {\n return this._nodeIndex.size;\n }\n\n // ── Validation ────────────────────────────────────────────────────────────\n\n validate(): DiagnosticCollector {\n const dc = new DiagnosticCollector();\n\n this.walk((node) => {\n // Validate event handler references exist\n for (const event of node.events) {\n if (!this.handlers.has(event.handlerKey)) {\n dc.warn(\n 'GRAPH_MISSING_HANDLER',\n `Node \"${node.id}\" references handler \"${event.handlerKey}\" which is not registered`,\n { nodeId: node.id },\n );\n }\n }\n\n // Validate page nodes are direct children of root\n if (node.type === 'page' && node.parent?.type !== 'application') {\n dc.error(\n 'GRAPH_PAGE_DEPTH',\n `Page node \"${node.id}\" must be a direct child of the application root`,\n { nodeId: node.id },\n );\n }\n });\n\n return dc;\n }\n\n // ── Serialization ─────────────────────────────────────────────────────────\n\n serialize(): SerializedGraph {\n return {\n name: this.name,\n version: this.version,\n root: this._serializeNode(this.root),\n };\n }\n\n private _serializeNode(node: GraphNode): SerializedNode {\n const result: SerializedNode = {\n id: node.id,\n type: node.type,\n key: node.key,\n props: node.props,\n events: node.events,\n stateRefs: node.stateRefs,\n children: node.children.map(c => this._serializeNode(c)),\n };\n return result;\n }\n}\n\nexport interface SerializedNode {\n readonly id: string;\n readonly type: string;\n readonly key: string | undefined;\n readonly props: Props;\n readonly events: EventDescriptor[];\n readonly stateRefs: unknown[];\n readonly children: SerializedNode[];\n}\n\nexport interface SerializedGraph {\n readonly name: string;\n readonly version: string;\n readonly root: SerializedNode;\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@streetui/graph",
3
+ "version": "1.0.0",
4
+ "description": "StreetUI Semantic Application Graph — nodes, relationships, traversal, validation",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "vitest run",
25
+ "clean": "rm -rf dist"
26
+ },
27
+ "dependencies": {
28
+ "@streetui/core": "1.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "*",
32
+ "tsup": "*",
33
+ "vitest": "*"
34
+ },
35
+ "license": "MIT",
36
+ "sideEffects": false,
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "README.md",
43
+ "LICENSE"
44
+ ]
45
+ }