0
# Graph Utilities
1
2
Graph analysis utilities for workflow structure analysis, node relationship mapping, subgraph extraction, and workflow optimization operations.
3
4
## Capabilities
5
6
### Adjacency List Construction
7
8
Build adjacency lists for efficient graph traversal and analysis.
9
10
```typescript { .api }
11
/**
12
* Build adjacency list from workflow connections
13
* @param connections - Workflow connections object
14
* @returns Adjacency list for graph traversal
15
*/
16
function buildAdjacencyList(connections: IConnections): AdjacencyList;
17
18
/**
19
* Adjacency list type for representing graph connections
20
*/
21
type AdjacencyList = Record<string, Array<{
22
node: string;
23
type: NodeConnectionType;
24
index: number;
25
}>>;
26
27
type NodeConnectionType = 'main' | 'ai_tool' | 'ai_agent' | 'ai_chain' | 'ai_document';
28
```
29
30
### Subgraph Extraction
31
32
Extract and analyze subgraphs from workflow structures.
33
34
```typescript { .api }
35
/**
36
* Parse extractable subgraph selection
37
* @param selection - Subgraph selection criteria
38
* @returns Parsed subgraph data structure
39
*/
40
function parseExtractableSubgraphSelection(
41
selection: string | ISubgraphSelection
42
): ExtractableSubgraphData | ExtractableErrorResult;
43
44
/**
45
* Subgraph data structure containing nodes and connections
46
*/
47
interface ExtractableSubgraphData {
48
nodes: string[];
49
connections: IConnection[];
50
entryNodes: string[];
51
exitNodes: string[];
52
metadata?: ISubgraphMetadata;
53
}
54
55
/**
56
* Error result for failed subgraph extraction
57
*/
58
interface ExtractableErrorResult {
59
error: string;
60
code: 'INVALID_SELECTION' | 'MISSING_NODES' | 'CIRCULAR_DEPENDENCY' | 'DISCONNECTED_GRAPH';
61
details?: IDataObject;
62
}
63
64
interface ISubgraphSelection {
65
nodeNames?: string[];
66
nodeTypes?: string[];
67
startNode?: string;
68
endNode?: string;
69
maxDepth?: number;
70
includeDisabled?: boolean;
71
}
72
73
interface ISubgraphMetadata {
74
nodeCount: number;
75
connectionCount: number;
76
depth: number;
77
hasCircularDependencies: boolean;
78
}
79
```
80
81
### Node Relationship Analysis
82
83
Analyze relationships between nodes in workflow graphs.
84
85
```typescript { .api }
86
/**
87
* Get all parent nodes of a specific node
88
* @param workflow - Workflow instance
89
* @param nodeName - Target node name
90
* @returns Array of parent node names
91
*/
92
function getParentNodes(workflow: Workflow, nodeName: string): string[];
93
94
/**
95
* Get all child nodes of a specific node
96
* @param workflow - Workflow instance
97
* @param nodeName - Target node name
98
* @returns Array of child node names
99
*/
100
function getChildNodes(workflow: Workflow, nodeName: string): string[];
101
102
/**
103
* Get all connected nodes (parents and children)
104
* @param workflow - Workflow instance
105
* @param nodeName - Target node name
106
* @returns Array of connected node names
107
*/
108
function getConnectedNodes(workflow: Workflow, nodeName: string): string[];
109
110
/**
111
* Find node by name in workflow
112
* @param workflow - Workflow instance
113
* @param nodeName - Node name to find
114
* @returns Node object or null if not found
115
*/
116
function getNodeByName(workflow: Workflow, nodeName: string): INode | null;
117
```
118
119
### Connection Mapping
120
121
Map and analyze workflow connections for optimization and validation.
122
123
```typescript { .api }
124
/**
125
* Map connections by their destination nodes
126
* @param connections - Workflow connections
127
* @returns Map of destination nodes to their input connections
128
*/
129
function mapConnectionsByDestination(
130
connections: IConnections
131
): IConnectionMap;
132
133
interface IConnectionMap {
134
[destinationNode: string]: Array<{
135
sourceNode: string;
136
sourceType: NodeConnectionType;
137
sourceIndex: number;
138
destinationType: NodeConnectionType;
139
destinationIndex: number;
140
}>;
141
}
142
143
/**
144
* Get connection path between two nodes
145
* @param workflow - Workflow instance
146
* @param startNode - Starting node name
147
* @param endNode - Target node name
148
* @returns Connection path or null if no path exists
149
*/
150
function getConnectionPath(
151
workflow: Workflow,
152
startNode: string,
153
endNode: string
154
): IConnectionPath | null;
155
156
interface IConnectionPath {
157
nodes: string[];
158
connections: IConnection[];
159
length: number;
160
isDirectConnection: boolean;
161
}
162
```
163
164
### Graph Analysis Functions
165
166
Advanced graph analysis for workflow optimization and validation.
167
168
```typescript { .api }
169
/**
170
* Detect circular dependencies in workflow
171
* @param workflow - Workflow instance
172
* @returns Array of circular dependency chains
173
*/
174
function detectCircularDependencies(workflow: Workflow): string[][];
175
176
/**
177
* Find disconnected nodes in workflow
178
* @param workflow - Workflow instance
179
* @returns Array of disconnected node names
180
*/
181
function findDisconnectedNodes(workflow: Workflow): string[];
182
183
/**
184
* Calculate workflow execution order
185
* @param workflow - Workflow instance
186
* @param startNodes - Optional starting nodes
187
* @returns Topologically sorted execution order
188
*/
189
function calculateExecutionOrder(
190
workflow: Workflow,
191
startNodes?: string[]
192
): string[];
193
194
/**
195
* Analyze workflow complexity metrics
196
* @param workflow - Workflow instance
197
* @returns Complexity analysis results
198
*/
199
function analyzeWorkflowComplexity(workflow: Workflow): IComplexityAnalysis;
200
201
interface IComplexityAnalysis {
202
nodeCount: number;
203
connectionCount: number;
204
maxDepth: number;
205
branchingFactor: number;
206
cyclomaticComplexity: number;
207
hasCycles: boolean;
208
disconnectedComponents: number;
209
}
210
```
211
212
### Graph Traversal Utilities
213
214
Utilities for traversing workflow graphs with different strategies.
215
216
```typescript { .api }
217
/**
218
* Depth-first search traversal
219
* @param workflow - Workflow instance
220
* @param startNode - Starting node name
221
* @param visitFn - Function called for each visited node
222
* @param options - Traversal options
223
*/
224
function depthFirstSearch(
225
workflow: Workflow,
226
startNode: string,
227
visitFn: (node: INode, depth: number) => boolean | void,
228
options?: ITraversalOptions
229
): void;
230
231
/**
232
* Breadth-first search traversal
233
* @param workflow - Workflow instance
234
* @param startNode - Starting node name
235
* @param visitFn - Function called for each visited node
236
* @param options - Traversal options
237
*/
238
function breadthFirstSearch(
239
workflow: Workflow,
240
startNode: string,
241
visitFn: (node: INode, level: number) => boolean | void,
242
options?: ITraversalOptions
243
): void;
244
245
interface ITraversalOptions {
246
maxDepth?: number;
247
includeDisabled?: boolean;
248
skipVisited?: boolean;
249
connectionTypes?: NodeConnectionType[];
250
}
251
252
/**
253
* Find shortest path between nodes
254
* @param workflow - Workflow instance
255
* @param startNode - Starting node name
256
* @param endNode - Target node name
257
* @returns Shortest path or null if no path exists
258
*/
259
function findShortestPath(
260
workflow: Workflow,
261
startNode: string,
262
endNode: string
263
): string[] | null;
264
```
265
266
### Graph Validation
267
268
Validation functions for workflow graph integrity and consistency.
269
270
```typescript { .api }
271
/**
272
* Validate workflow graph structure
273
* @param workflow - Workflow instance
274
* @returns Validation results with errors and warnings
275
*/
276
function validateWorkflowGraph(workflow: Workflow): IGraphValidationResult;
277
278
interface IGraphValidationResult {
279
isValid: boolean;
280
errors: IGraphValidationError[];
281
warnings: IGraphValidationWarning[];
282
}
283
284
interface IGraphValidationError {
285
type: 'MISSING_NODE' | 'INVALID_CONNECTION' | 'CIRCULAR_DEPENDENCY' | 'DISCONNECTED_NODE';
286
message: string;
287
affectedNodes: string[];
288
severity: 'high' | 'medium' | 'low';
289
}
290
291
interface IGraphValidationWarning {
292
type: 'UNUSED_NODE' | 'COMPLEX_PATH' | 'PERFORMANCE_CONCERN';
293
message: string;
294
affectedNodes: string[];
295
suggestion?: string;
296
}
297
298
/**
299
* Check if workflow has valid execution paths
300
* @param workflow - Workflow instance
301
* @returns Boolean indicating if workflow has valid paths
302
*/
303
function hasValidExecutionPaths(workflow: Workflow): boolean;
304
305
/**
306
* Validate node connections
307
* @param workflow - Workflow instance
308
* @param nodeName - Node to validate connections for
309
* @returns Connection validation result
310
*/
311
function validateNodeConnections(
312
workflow: Workflow,
313
nodeName: string
314
): IConnectionValidationResult;
315
316
interface IConnectionValidationResult {
317
isValid: boolean;
318
invalidConnections: string[];
319
missingRequiredInputs: string[];
320
extraneousOutputs: string[];
321
}
322
```
323
324
**Usage Examples:**
325
326
```typescript
327
import {
328
buildAdjacencyList,
329
parseExtractableSubgraphSelection,
330
getParentNodes,
331
getChildNodes,
332
mapConnectionsByDestination,
333
detectCircularDependencies,
334
calculateExecutionOrder,
335
depthFirstSearch,
336
validateWorkflowGraph
337
} from "n8n-workflow";
338
339
// Build adjacency list for graph analysis
340
const adjacencyList = buildAdjacencyList(workflow.getConnections());
341
console.log('Adjacency list:', adjacencyList);
342
343
// Extract subgraph
344
const subgraphResult = parseExtractableSubgraphSelection({
345
nodeNames: ['Start', 'HTTP Request', 'Data Transform'],
346
includeDisabled: false
347
});
348
349
if ('error' in subgraphResult) {
350
console.log('Subgraph extraction failed:', subgraphResult.error);
351
} else {
352
console.log('Extracted subgraph nodes:', subgraphResult.nodes);
353
console.log('Entry nodes:', subgraphResult.entryNodes);
354
console.log('Exit nodes:', subgraphResult.exitNodes);
355
}
356
357
// Analyze node relationships
358
const parents = getParentNodes(workflow, 'Data Transform');
359
const children = getChildNodes(workflow, 'HTTP Request');
360
const connected = getConnectedNodes(workflow, 'Start');
361
362
console.log('Parent nodes of Data Transform:', parents);
363
console.log('Child nodes of HTTP Request:', children);
364
console.log('All connected nodes to Start:', connected);
365
366
// Map connections by destination
367
const connectionMap = mapConnectionsByDestination(workflow.getConnections());
368
Object.entries(connectionMap).forEach(([destNode, connections]) => {
369
console.log(`${destNode} receives input from:`, connections);
370
});
371
372
// Detect circular dependencies
373
const cycles = detectCircularDependencies(workflow);
374
if (cycles.length > 0) {
375
console.log('Circular dependencies detected:');
376
cycles.forEach((cycle, index) => {
377
console.log(`Cycle ${index + 1}: ${cycle.join(' -> ')}`);
378
});
379
}
380
381
// Calculate execution order
382
const executionOrder = calculateExecutionOrder(workflow);
383
console.log('Execution order:', executionOrder);
384
385
// Traverse workflow graph
386
depthFirstSearch(
387
workflow,
388
'Start',
389
(node, depth) => {
390
console.log(`${' '.repeat(depth)}Visiting: ${node.name} (${node.type})`);
391
392
// Return true to stop traversal, false/void to continue
393
if (depth > 5) {
394
console.log('Max depth reached, stopping traversal');
395
return true;
396
}
397
},
398
{
399
maxDepth: 10,
400
includeDisabled: false
401
}
402
);
403
404
// Validate workflow graph
405
const validation = validateWorkflowGraph(workflow);
406
if (!validation.isValid) {
407
console.log('Workflow validation errors:');
408
validation.errors.forEach(error => {
409
console.log(`- ${error.type}: ${error.message}`);
410
console.log(` Affected nodes: ${error.affectedNodes.join(', ')}`);
411
});
412
}
413
414
if (validation.warnings.length > 0) {
415
console.log('Workflow validation warnings:');
416
validation.warnings.forEach(warning => {
417
console.log(`- ${warning.type}: ${warning.message}`);
418
if (warning.suggestion) {
419
console.log(` Suggestion: ${warning.suggestion}`);
420
}
421
});
422
}
423
424
// Complex workflow analysis
425
const complexity = analyzeWorkflowComplexity(workflow);
426
console.log('Workflow complexity analysis:');
427
console.log(`- Nodes: ${complexity.nodeCount}`);
428
console.log(`- Connections: ${complexity.connectionCount}`);
429
console.log(`- Max depth: ${complexity.maxDepth}`);
430
console.log(`- Branching factor: ${complexity.branchingFactor}`);
431
console.log(`- Cyclomatic complexity: ${complexity.cyclomaticComplexity}`);
432
console.log(`- Has cycles: ${complexity.hasCycles}`);
433
console.log(`- Disconnected components: ${complexity.disconnectedComponents}`);
434
435
// Find shortest path between nodes
436
const shortestPath = findShortestPath(workflow, 'Start', 'End');
437
if (shortestPath) {
438
console.log('Shortest path from Start to End:', shortestPath.join(' -> '));
439
} else {
440
console.log('No path found from Start to End');
441
}
442
443
// Breadth-first traversal to find all nodes at each level
444
const nodesByLevel: { [level: number]: string[] } = {};
445
breadthFirstSearch(
446
workflow,
447
'Start',
448
(node, level) => {
449
if (!nodesByLevel[level]) {
450
nodesByLevel[level] = [];
451
}
452
nodesByLevel[level].push(node.name);
453
}
454
);
455
456
console.log('Nodes by execution level:');
457
Object.entries(nodesByLevel).forEach(([level, nodes]) => {
458
console.log(`Level ${level}: ${nodes.join(', ')}`);
459
});
460
```