@@ -27,10 +27,6 @@ const catchReference = '/catch';
2727const branchReference = '/fork/branches' ;
2828const tryReference = '/try' ;
2929
30- function exists < T > ( obj : T | undefined ) : obj is T {
31- return ! ! obj ;
32- }
33-
3430/**
3531 * Represents a generic within a graph.
3632 * This serves as a base type for nodes, edges, and graphs.
@@ -75,6 +71,8 @@ export type GraphNode = GraphElement & {
7571 type : GraphNodeType ;
7672 /** The parent graph, if any. */
7773 parent ?: Graph ;
74+ /** The related task */
75+ task ?: Task ;
7876} ;
7977
8078/**
@@ -161,13 +159,15 @@ function mapTasks(tasksList: TaskItem[] | undefined): Map<string, Task> {
161159 *
162160 * @param type The type of the graph node.
163161 * @param id Unique identifier for the graph.
162+ * @param task The related task
164163 * @param label Optional label for the graph.
165164 * @param parent Optional parent graph if this is a subgraph.
166165 * @returns A newly created Graph instance.
167166 */
168167function initGraph (
169168 type : GraphNodeType ,
170169 id : string = rootId ,
170+ task : Task | undefined = undefined ,
171171 label : string | undefined = undefined ,
172172 parent : Graph | undefined = undefined ,
173173) : Graph {
@@ -176,6 +176,7 @@ function initGraph(
176176 label,
177177 type,
178178 parent,
179+ task,
179180 nodes : [ ] ,
180181 edges : [ ] ,
181182 } ;
@@ -274,7 +275,7 @@ function buildTransition(sourceNode: GraphNode | Graph, transition: TransitionIn
274275 transition . label ,
275276 ) ;
276277 } else if ( transition . name === FlowDirective . Exit ) {
277- if ( ! exists ( context . graph . exitNode ) ) throw new Error ( `Missing exit node on graph id '${ context . graph . id } '` ) ;
278+ if ( ! context . graph . exitNode ) throw new Error ( `Missing exit node on graph id '${ context . graph . id } '` ) ;
278279 buildEdge ( context . graph , context . knownEdges , exitAnchor , context . graph . exitNode , transition . label ) ;
279280 } else if ( transition . name === FlowDirective . End ) {
280281 buildEdge ( context . graph , context . knownEdges , exitAnchor , getEndNode ( context . graph ) , transition . label ) ;
@@ -336,8 +337,9 @@ function buildTaskNode(context: TaskContext): GraphNode | Graph {
336337 * @param context The context to build the graph node for
337338 * @returns A graph node for the provided context
338339 */
339- function buildGenericTaskNode ( type : GraphNodeType , context : TaskContext ) : GraphNode {
340+ function buildGenericTaskNode ( task : Task , type : GraphNodeType , context : TaskContext ) : GraphNode {
340341 const node : GraphNode = {
342+ task,
341343 type,
342344 parent : context . graph ,
343345 id : context . taskReference ,
@@ -355,7 +357,7 @@ function buildGenericTaskNode(type: GraphNodeType, context: TaskContext): GraphN
355357 * @returns A graph node for the provided task
356358 */
357359function buildCallTaskNode ( task : CallTask , context : TaskContext ) : GraphNode {
358- const node = buildGenericTaskNode ( GraphNodeType . Call , context ) ;
360+ const node = buildGenericTaskNode ( task , GraphNodeType . Call , context ) ;
359361 // TODO: add some details about the task?
360362 return node ;
361363}
@@ -367,15 +369,15 @@ function buildCallTaskNode(task: CallTask, context: TaskContext): GraphNode {
367369 * @returns A graph for the provided task
368370 */
369371function buildDoTaskNode ( task : DoTask , context : TaskContext ) : Graph {
370- const subgraph : Graph = initGraph ( GraphNodeType . Do , context . taskReference , context . taskName , context . graph ) ;
372+ const subgraph : Graph = initGraph ( GraphNodeType . Do , context . taskReference , task , context . taskName , context . graph ) ;
371373 const doContext : TaskContext = {
372374 ...context ,
373375 graph : subgraph ,
374376 taskListReference : context . taskReference + doReference ,
375377 taskList : mapTasks ( task . do ) ,
376378 taskName : undefined ,
377379 } ;
378- if ( ! exists ( subgraph . entryNode ) ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
380+ if ( ! subgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
379381 buildTransitions ( subgraph . entryNode , doContext ) ;
380382 buildTransitions ( subgraph , context ) ;
381383 return subgraph ;
@@ -388,7 +390,7 @@ function buildDoTaskNode(task: DoTask, context: TaskContext): Graph {
388390 * @returns A graph node for the provided task
389391 */
390392function buildEmitTaskNode ( task : EmitTask , context : TaskContext ) : GraphNode {
391- const node = buildGenericTaskNode ( GraphNodeType . Emit , context ) ;
393+ const node = buildGenericTaskNode ( task , GraphNodeType . Emit , context ) ;
392394 // TODO: add some details about the task?
393395 return node ;
394396}
@@ -400,15 +402,15 @@ function buildEmitTaskNode(task: EmitTask, context: TaskContext): GraphNode {
400402 * @returns A graph for the provided task
401403 */
402404function buildForTaskNode ( task : ForTask , context : TaskContext ) : Graph {
403- const subgraph : Graph = initGraph ( GraphNodeType . For , context . taskReference , context . taskName , context . graph ) ;
405+ const subgraph : Graph = initGraph ( GraphNodeType . For , context . taskReference , task , context . taskName , context . graph ) ;
404406 const forContext : TaskContext = {
405407 ...context ,
406408 graph : subgraph ,
407409 taskListReference : subgraph . id + forReference + doReference ,
408410 taskList : mapTasks ( task . do ) ,
409411 taskName : undefined ,
410412 } ;
411- if ( ! exists ( subgraph . entryNode ) ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
413+ if ( ! subgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
412414 buildTransitions ( subgraph . entryNode , forContext ) ;
413415 buildTransitions ( subgraph , context ) ;
414416 return subgraph ;
@@ -421,7 +423,7 @@ function buildForTaskNode(task: ForTask, context: TaskContext): Graph {
421423 * @returns A graph for the provided task
422424 */
423425function buildForkTaskNode ( task : ForkTask , context : TaskContext ) : Graph {
424- const subgraph : Graph = initGraph ( GraphNodeType . Fork , context . taskReference , context . taskName , context . graph ) ;
426+ const subgraph : Graph = initGraph ( GraphNodeType . Fork , context . taskReference , task , context . taskName , context . graph ) ;
425427 for ( let i = 0 , c = task . fork ?. branches . length || 0 ; i < c ; i ++ ) {
426428 const branchItem = task . fork ?. branches [ i ] ;
427429 if ( ! branchItem ) continue ;
@@ -435,8 +437,8 @@ function buildForkTaskNode(task: ForkTask, context: TaskContext): Graph {
435437 taskName : branchName ,
436438 } ;
437439 const branchNode = buildTaskNode ( branchContext ) ;
438- if ( ! exists ( subgraph . entryNode ) ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
439- if ( ! exists ( subgraph . exitNode ) ) throw new Error ( `Missing 'exitNode' on graph id '${ subgraph . id } '` ) ;
440+ if ( ! subgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ subgraph . id } '` ) ;
441+ if ( ! subgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ subgraph . id } '` ) ;
440442 buildEdge ( subgraph , context . knownEdges , subgraph . entryNode , ( branchNode as Graph ) . entryNode || branchNode ) ;
441443 buildEdge ( subgraph , context . knownEdges , ( branchNode as Graph ) . exitNode || branchNode , subgraph . exitNode ) ;
442444 }
@@ -451,7 +453,7 @@ function buildForkTaskNode(task: ForkTask, context: TaskContext): Graph {
451453 * @returns A graph node for the provided task
452454 */
453455function buildListenTaskNode ( task : ListenTask , context : TaskContext ) : GraphNode {
454- const node = buildGenericTaskNode ( GraphNodeType . Listen , context ) ;
456+ const node = buildGenericTaskNode ( task , GraphNodeType . Listen , context ) ;
455457 // TODO: add some details about the task?
456458 return node ;
457459}
@@ -463,7 +465,7 @@ function buildListenTaskNode(task: ListenTask, context: TaskContext): GraphNode
463465 * @returns A graph node for the provided task
464466 */
465467function buildRaiseTaskNode ( task : RaiseTask , context : TaskContext ) : GraphNode {
466- const node = buildGenericTaskNode ( GraphNodeType . Raise , context ) ;
468+ const node = buildGenericTaskNode ( task , GraphNodeType . Raise , context ) ;
467469 // TODO: add some details about the task?
468470 return node ;
469471}
@@ -475,7 +477,7 @@ function buildRaiseTaskNode(task: RaiseTask, context: TaskContext): GraphNode {
475477 * @returns A graph node for the provided task
476478 */
477479function buildRunTaskNode ( task : RunTask , context : TaskContext ) : GraphNode {
478- const node = buildGenericTaskNode ( GraphNodeType . Run , context ) ;
480+ const node = buildGenericTaskNode ( task , GraphNodeType . Run , context ) ;
479481 // TODO: add some details about the task?
480482 return node ;
481483}
@@ -487,7 +489,7 @@ function buildRunTaskNode(task: RunTask, context: TaskContext): GraphNode {
487489 * @returns A graph node for the provided task
488490 */
489491function buildSetTaskNode ( task : SetTask , context : TaskContext ) : GraphNode {
490- const node = buildGenericTaskNode ( GraphNodeType . Set , context ) ;
492+ const node = buildGenericTaskNode ( task , GraphNodeType . Set , context ) ;
491493 // TODO: add some details about the task?
492494 return node ;
493495}
@@ -499,7 +501,7 @@ function buildSetTaskNode(task: SetTask, context: TaskContext): GraphNode {
499501 * @returns A graph node for the provided task
500502 */
501503function buildSwitchTaskNode ( task : SwitchTask , context : TaskContext ) : GraphNode {
502- const node : GraphNode = buildGenericTaskNode ( GraphNodeType . Switch , context ) ;
504+ const node : GraphNode = buildGenericTaskNode ( task , GraphNodeType . Switch , context ) ;
503505 let hasDefaultCase = false ;
504506 task . switch ?. forEach ( ( switchItem ) => {
505507 const [ caseName , switchCase ] = Object . entries ( switchItem ) [ 0 ] ;
@@ -524,18 +526,19 @@ function buildTryCatchTaskNode(task: TryTask, context: TaskContext): Graph {
524526 const containerSubgraph : Graph = initGraph (
525527 GraphNodeType . TryCatch ,
526528 context . taskReference ,
529+ task ,
527530 context . taskName ,
528531 context . graph ,
529532 ) ;
530533 const trySubgraph : Graph = initGraph (
531534 GraphNodeType . Try ,
532535 context . taskReference + tryReference ,
536+ task ,
533537 context . taskName + ' (try)' ,
534538 containerSubgraph ,
535539 ) ;
536- if ( ! exists ( containerSubgraph . entryNode ) )
537- throw new Error ( `Missing 'entryNode' on graph id '${ containerSubgraph . id } '` ) ;
538- if ( ! exists ( trySubgraph . entryNode ) ) throw new Error ( `Missing 'entryNode' on graph id '${ trySubgraph . id } '` ) ;
540+ if ( ! containerSubgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ containerSubgraph . id } '` ) ;
541+ if ( ! trySubgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ trySubgraph . id } '` ) ;
539542 buildEdge ( containerSubgraph , context . knownEdges , containerSubgraph . entryNode , trySubgraph . entryNode ) ;
540543 const tryContext : TaskContext = {
541544 ...context ,
@@ -544,31 +547,31 @@ function buildTryCatchTaskNode(task: TryTask, context: TaskContext): Graph {
544547 taskList : mapTasks ( task . try ) ,
545548 taskName : undefined ,
546549 } ;
547- if ( ! exists ( trySubgraph . entryNode ) ) throw new Error ( `Missing 'entryNode' on graph id '${ trySubgraph . id } '` ) ;
550+ if ( ! trySubgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ trySubgraph . id } '` ) ;
548551 buildTransitions ( trySubgraph . entryNode , tryContext ) ;
549552 if ( ! task . catch ?. do ?. length ) {
550553 const catchNode : GraphNode = {
554+ task,
551555 type : GraphNodeType . Catch ,
552556 parent : containerSubgraph ,
553557 id : context . taskReference + catchReference ,
554558 label : context . taskName + ' (catch)' ,
555559 } ;
556560 containerSubgraph . nodes . push ( catchNode ) ;
557- if ( ! exists ( trySubgraph . exitNode ) ) throw new Error ( `Missing 'exitNode' on graph id '${ trySubgraph . id } '` ) ;
558- if ( ! exists ( containerSubgraph . exitNode ) )
559- throw new Error ( `Missing 'exitNode' on graph id '${ containerSubgraph . id } '` ) ;
561+ if ( ! trySubgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ trySubgraph . id } '` ) ;
562+ if ( ! containerSubgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ containerSubgraph . id } '` ) ;
560563 buildEdge ( containerSubgraph , context . knownEdges , trySubgraph . exitNode , catchNode ) ;
561564 buildEdge ( containerSubgraph , context . knownEdges , catchNode , containerSubgraph . exitNode ) ;
562565 } else {
563566 const catchSubgraph : Graph = initGraph (
564567 GraphNodeType . Catch ,
565568 context . taskReference + catchReference + doReference ,
569+ task ,
566570 context . taskName + ' (catch)' ,
567571 containerSubgraph ,
568572 ) ;
569- if ( ! exists ( trySubgraph . exitNode ) ) throw new Error ( `Missing 'exitNode' on graph id '${ trySubgraph . id } '` ) ;
570- if ( ! exists ( catchSubgraph . entryNode ) )
571- throw new Error ( `Missing 'entryNode' on graph id '${ catchSubgraph . entryNode } '` ) ;
573+ if ( ! trySubgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ trySubgraph . id } '` ) ;
574+ if ( ! catchSubgraph . entryNode ) throw new Error ( `Missing 'entryNode' on graph id '${ catchSubgraph . entryNode } '` ) ;
572575 buildEdge ( containerSubgraph , context . knownEdges , trySubgraph . exitNode , catchSubgraph . entryNode ) ;
573576 const catchContext : TaskContext = {
574577 ...context ,
@@ -578,9 +581,8 @@ function buildTryCatchTaskNode(task: TryTask, context: TaskContext): Graph {
578581 taskName : undefined ,
579582 } ;
580583 buildTransitions ( catchSubgraph . entryNode , catchContext ) ;
581- if ( ! exists ( catchSubgraph . exitNode ) ) throw new Error ( `Missing 'exitNode' on graph id '${ catchSubgraph . exitNode } '` ) ;
582- if ( ! exists ( containerSubgraph . exitNode ) )
583- throw new Error ( `Missing 'exitNode' on graph id '${ containerSubgraph . exitNode } '` ) ;
584+ if ( ! catchSubgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ catchSubgraph . exitNode } '` ) ;
585+ if ( ! containerSubgraph . exitNode ) throw new Error ( `Missing 'exitNode' on graph id '${ containerSubgraph . exitNode } '` ) ;
584586 buildEdge ( containerSubgraph , context . knownEdges , catchSubgraph . exitNode , containerSubgraph . exitNode ) ;
585587 }
586588 buildTransitions ( containerSubgraph , context ) ;
@@ -594,7 +596,7 @@ function buildTryCatchTaskNode(task: TryTask, context: TaskContext): Graph {
594596 * @returns A graph node for the provided task
595597 */
596598function buildWaitTaskNode ( task : WaitTask , context : TaskContext ) : GraphNode {
597- const node = buildGenericTaskNode ( GraphNodeType . Wait , context ) ;
599+ const node = buildGenericTaskNode ( task , GraphNodeType . Wait , context ) ;
598600 // TODO: add some details about the task?
599601 return node ;
600602}
@@ -627,7 +629,7 @@ function buildEdge(graph: Graph, knownEdges: GraphEdge[], source: GraphNode, tar
627629 * Remaps edges by getting rid of routes leading to entry/exit nodes
628630 * @param edges
629631 */
630- const remapEdges = ( edges : GraphEdge [ ] ) : GraphEdge [ ] => {
632+ export const remapEdges = ( edges : GraphEdge [ ] ) : GraphEdge [ ] => {
631633 let remappedEdges = [ ...edges . map ( ( e ) => ( { ...e } ) ) ] ;
632634 const leadsToPort = ( edge : GraphEdge ) =>
633635 edge . targetId !== 'root-exit-node' &&
@@ -675,7 +677,7 @@ const remapEdges = (edges: GraphEdge[]): GraphEdge[] => {
675677 * @param graph The graph to flatten the edges of
676678 * @returns All the edge declared in the graph and its subgraphs
677679 */
678- const flattenEdges = ( graph : Graph ) : GraphEdge [ ] => [
680+ export const flattenEdges = ( graph : Graph ) : GraphEdge [ ] => [
679681 ...( graph . edges || [ ] ) ,
680682 ...( ( graph . nodes || [ ] ) . filter ( ( node ) => ( node as Graph ) . edges ?. length ) as Graph [ ] ) . flatMap ( flattenEdges ) ,
681683] ;
@@ -685,7 +687,7 @@ const flattenEdges = (graph: Graph): GraphEdge[] => [
685687 * @param graph The graph/node to flatten the nodes of
686688 * @returns All the nodes and subnodes declared in the graph
687689 */
688- const flattenNodes = ( node : Graph | GraphNode ) : Array < Graph | GraphNode > => [
690+ export const flattenNodes = ( node : Graph | GraphNode ) : Array < Graph | GraphNode > => [
689691 {
690692 ...node ,
691693 entryNode : undefined ,
@@ -701,7 +703,7 @@ const flattenNodes = (node: Graph | GraphNode): Array<Graph | GraphNode> => [
701703 * @param graph The target graph
702704 * @returns The modified graph
703705 */
704- function flattenGraph ( graph : Graph ) : Graph {
706+ export function flattenGraph ( graph : Graph ) : Graph {
705707 const edges = remapEdges ( flattenEdges ( graph ) ) ;
706708 const nodes = graph . nodes
707709 . flatMap ( ( node ) => flattenNodes ( node ) )
@@ -718,7 +720,7 @@ function flattenGraph(graph: Graph): Graph {
718720 * Constructs a graph representation based on the given workflow.
719721 *
720722 * @param workflow The workflow to be converted into a graph structure.
721- * @param simplifyGraph A boolean indicating whether the graph should be flattened and free of internal entry/exit nodes.
723+ * @param simplifyGraph A boolean indicating whether the graph nodes & edges should be flattened and free of internal entry/exit nodes.
722724 * @returns A graph representation of the workflow.
723725 */
724726export function buildGraph ( workflow : Workflow , simplifyGraph : boolean = false ) : Graph {
0 commit comments