@tracegraph/graph-engine 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -31,6 +31,12 @@ type GraphNode = {
31
31
  size: number;
32
32
  /** The original TraceEvent that produced this node. */
33
33
  data: TraceEvent;
34
+ /**
35
+ * Set when this node represents N collapsed siblings of the same type.
36
+ * The label will already include the count; this field allows renderers
37
+ * to display a badge or different visual treatment.
38
+ */
39
+ collapsedCount?: number;
34
40
  };
35
41
  type GraphEdgeType = 'parent' | 'parallel_branch';
36
42
  type GraphEdge = {
package/dist/index.d.ts CHANGED
@@ -31,6 +31,12 @@ type GraphNode = {
31
31
  size: number;
32
32
  /** The original TraceEvent that produced this node. */
33
33
  data: TraceEvent;
34
+ /**
35
+ * Set when this node represents N collapsed siblings of the same type.
36
+ * The label will already include the count; this field allows renderers
37
+ * to display a badge or different visual treatment.
38
+ */
39
+ collapsedCount?: number;
34
40
  };
35
41
  type GraphEdgeType = 'parent' | 'parallel_branch';
36
42
  type GraphEdge = {
package/dist/index.js CHANGED
@@ -170,7 +170,74 @@ function traceSessionToGraph(session) {
170
170
  edges.push({ id: edgeId, source: sourceNodeId, target: targetNodeId, type: edgeType });
171
171
  }
172
172
  }
173
- return { nodes, edges, captureLevel: session.captureLevel };
173
+ return collapseSiblings({ nodes, edges, captureLevel: session.captureLevel });
174
+ }
175
+ var SIBLING_COLLAPSE_THRESHOLD = 5;
176
+ function collapseSiblings(graph) {
177
+ const { nodes, edges, captureLevel } = graph;
178
+ if (nodes.length <= SIBLING_COLLAPSE_THRESHOLD * 2) {
179
+ return graph;
180
+ }
181
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
182
+ const childrenByParent = /* @__PURE__ */ new Map();
183
+ for (const edge of edges) {
184
+ if (!childrenByParent.has(edge.source)) {
185
+ childrenByParent.set(edge.source, /* @__PURE__ */ new Map());
186
+ }
187
+ const target = nodeById.get(edge.target);
188
+ if (!target) continue;
189
+ const typeMap = childrenByParent.get(edge.source);
190
+ if (!typeMap.has(target.type)) typeMap.set(target.type, []);
191
+ typeMap.get(target.type).push(edge.target);
192
+ }
193
+ const willCollapse = /* @__PURE__ */ new Set();
194
+ for (const typeMap of childrenByParent.values()) {
195
+ for (const nodeIds of typeMap.values()) {
196
+ if (nodeIds.length >= SIBLING_COLLAPSE_THRESHOLD) {
197
+ for (const id of nodeIds) willCollapse.add(id);
198
+ }
199
+ }
200
+ }
201
+ if (willCollapse.size === 0) return graph;
202
+ const summaryNodes = [];
203
+ const summaryEdges = [];
204
+ for (const [parentId, typeMap] of childrenByParent) {
205
+ if (willCollapse.has(parentId)) continue;
206
+ for (const [type, nodeIds] of typeMap) {
207
+ if (nodeIds.length < SIBLING_COLLAPSE_THRESHOLD) continue;
208
+ const first = nodeById.get(nodeIds[0]);
209
+ const typeName = type.replace(/_/g, " ");
210
+ const summaryId = `summary__${parentId}__${type}`;
211
+ summaryNodes.push({
212
+ id: summaryId,
213
+ label: `${typeName} \xD7${nodeIds.length}`,
214
+ type,
215
+ language: first.language,
216
+ framework: first.framework,
217
+ color: first.color,
218
+ size: Math.min(10, Math.ceil(Math.log10(nodeIds.length + 1)) + 3),
219
+ collapsedCount: nodeIds.length,
220
+ data: first.data
221
+ });
222
+ summaryEdges.push({
223
+ id: `${parentId}\u2192${summaryId}`,
224
+ source: parentId,
225
+ target: summaryId,
226
+ type: "parent"
227
+ });
228
+ }
229
+ }
230
+ return {
231
+ nodes: [
232
+ ...nodes.filter((n) => !willCollapse.has(n.id)),
233
+ ...summaryNodes
234
+ ],
235
+ edges: [
236
+ ...edges.filter((e) => !willCollapse.has(e.source) && !willCollapse.has(e.target)),
237
+ ...summaryEdges
238
+ ],
239
+ captureLevel
240
+ };
174
241
  }
175
242
 
176
243
  // src/signature.ts
package/dist/index.mjs CHANGED
@@ -132,7 +132,74 @@ function traceSessionToGraph(session) {
132
132
  edges.push({ id: edgeId, source: sourceNodeId, target: targetNodeId, type: edgeType });
133
133
  }
134
134
  }
135
- return { nodes, edges, captureLevel: session.captureLevel };
135
+ return collapseSiblings({ nodes, edges, captureLevel: session.captureLevel });
136
+ }
137
+ var SIBLING_COLLAPSE_THRESHOLD = 5;
138
+ function collapseSiblings(graph) {
139
+ const { nodes, edges, captureLevel } = graph;
140
+ if (nodes.length <= SIBLING_COLLAPSE_THRESHOLD * 2) {
141
+ return graph;
142
+ }
143
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
144
+ const childrenByParent = /* @__PURE__ */ new Map();
145
+ for (const edge of edges) {
146
+ if (!childrenByParent.has(edge.source)) {
147
+ childrenByParent.set(edge.source, /* @__PURE__ */ new Map());
148
+ }
149
+ const target = nodeById.get(edge.target);
150
+ if (!target) continue;
151
+ const typeMap = childrenByParent.get(edge.source);
152
+ if (!typeMap.has(target.type)) typeMap.set(target.type, []);
153
+ typeMap.get(target.type).push(edge.target);
154
+ }
155
+ const willCollapse = /* @__PURE__ */ new Set();
156
+ for (const typeMap of childrenByParent.values()) {
157
+ for (const nodeIds of typeMap.values()) {
158
+ if (nodeIds.length >= SIBLING_COLLAPSE_THRESHOLD) {
159
+ for (const id of nodeIds) willCollapse.add(id);
160
+ }
161
+ }
162
+ }
163
+ if (willCollapse.size === 0) return graph;
164
+ const summaryNodes = [];
165
+ const summaryEdges = [];
166
+ for (const [parentId, typeMap] of childrenByParent) {
167
+ if (willCollapse.has(parentId)) continue;
168
+ for (const [type, nodeIds] of typeMap) {
169
+ if (nodeIds.length < SIBLING_COLLAPSE_THRESHOLD) continue;
170
+ const first = nodeById.get(nodeIds[0]);
171
+ const typeName = type.replace(/_/g, " ");
172
+ const summaryId = `summary__${parentId}__${type}`;
173
+ summaryNodes.push({
174
+ id: summaryId,
175
+ label: `${typeName} \xD7${nodeIds.length}`,
176
+ type,
177
+ language: first.language,
178
+ framework: first.framework,
179
+ color: first.color,
180
+ size: Math.min(10, Math.ceil(Math.log10(nodeIds.length + 1)) + 3),
181
+ collapsedCount: nodeIds.length,
182
+ data: first.data
183
+ });
184
+ summaryEdges.push({
185
+ id: `${parentId}\u2192${summaryId}`,
186
+ source: parentId,
187
+ target: summaryId,
188
+ type: "parent"
189
+ });
190
+ }
191
+ }
192
+ return {
193
+ nodes: [
194
+ ...nodes.filter((n) => !willCollapse.has(n.id)),
195
+ ...summaryNodes
196
+ ],
197
+ edges: [
198
+ ...edges.filter((e) => !willCollapse.has(e.source) && !willCollapse.has(e.target)),
199
+ ...summaryEdges
200
+ ],
201
+ captureLevel
202
+ };
136
203
  }
137
204
 
138
205
  // src/signature.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracegraph/graph-engine",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Converts TraceSession to a graph structure; produces baselines, diffs, and findings",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -19,8 +19,8 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@tracegraph/trace-sanitizer": "0.1.4",
23
- "@tracegraph/shared-types": "0.1.4"
22
+ "@tracegraph/shared-types": "0.2.0",
23
+ "@tracegraph/trace-sanitizer": "0.2.0"
24
24
  },
25
25
  "scripts": {
26
26
  "build": "tsup src/index.ts --format cjs,esm --dts --external '@tracegraph/*'",