or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants.mddata-proxy.mderror-handling.mdexpression-system.mdextension-system.mdgraph-utilities.mdindex.mdnode-execution.mdspecialized-modules.mdtype-guards.mdtype-validation.mdutilities.mdworkflow-management.md

graph-utilities.mddocs/

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

```