Skip to content

Commit d059bf0

Browse files
committed
feat: added graph and mermaid features to workflow object
Signed-off-by: Jean-Baptiste Bianchi <[email protected]>
1 parent 3dfdfb2 commit d059bf0

File tree

11 files changed

+439
-247
lines changed

11 files changed

+439
-247
lines changed

README.md

+32-23
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ do:
110110
set:
111111
variable: 'my first workflow'
112112
`;
113-
const workflowDefinition = Classes.Workflow.deserialize(text);
113+
const workflow = Classes.Workflow.deserialize(text);
114114
```
115115

116116
#### Create a Workflow Definition by Casting an Object
@@ -120,7 +120,7 @@ You can type-cast an object to match the structure of a workflow definition:
120120
import { Classes, Specification, validate } from '@serverlessworkflow/sdk';
121121

122122
// Simply cast an object:
123-
const workflowDefinition = {
123+
const workflow = {
124124
document: {
125125
dsl: '1.0.0',
126126
name: 'test',
@@ -140,9 +140,9 @@ const workflowDefinition = {
140140

141141
// Validate it
142142
try {
143-
validate('Workflow', workflowDefinition);
143+
validate('Workflow', workflow);
144144
// Serialize it
145-
const definitionTxt = Classes.Workflow.serialize(workflowDefinition);
145+
const definitionTxt = Classes.Workflow.serialize(workflow);
146146
}
147147
catch (ex) {
148148
// Invalid workflow definition
@@ -156,7 +156,7 @@ You can create a workflow definition by calling a constructor:
156156
import { Classes, validate } from '@serverlessworkflow/sdk';
157157

158158
// Simply use the constructor
159-
const workflowDefinition = new Classes.Workflow({
159+
const workflow = new Classes.Workflow({
160160
document: {
161161
dsl: '1.0.0',
162162
name: 'test',
@@ -173,7 +173,7 @@ const workflowDefinition = new Classes.Workflow({
173173
},
174174
*/],
175175
});
176-
workflowDefinition.do.push({
176+
workflow.do.push({
177177
step1: new Classes.SetTask({
178178
set: {
179179
variable: 'my first workflow',
@@ -183,9 +183,9 @@ workflowDefinition.do.push({
183183

184184
// Validate it
185185
try {
186-
workflowDefinition.validate();
186+
workflow.validate();
187187
// Serialize it
188-
const definitionTxt = workflowDefinition.serialize();
188+
const definitionTxt = workflow.serialize();
189189
}
190190
catch (ex) {
191191
// Invalid workflow definition
@@ -198,7 +198,7 @@ You can use the fluent API to build a validated and normalized workflow definiti
198198
```typescript
199199
import { documentBuilder, setTaskBuilder, taskListBuilder, workflowBuilder } from '@serverlessworkflow/sdk';
200200

201-
const workflowDefinition = workflowBuilder(/*workflowDefinitionObject*/)
201+
const workflow = workflowBuilder(/*workflowObject*/)
202202
.document(
203203
documentBuilder()
204204
.dsl('1.0.0')
@@ -230,12 +230,12 @@ You can serialize a workflow definition either by using its `serialize` method i
230230
```typescript
231231
import { Classes } from '@serverlessworkflow/sdk';
232232

233-
// const workflowDefinition = <Your preferred method>;
234-
if (workflowDefinition instanceof Classes.Workflow) {
235-
const yaml = workflowDefinition.serialize(/*'yaml' | 'json' */);
233+
// const workflow = <Your preferred method>;
234+
if (workflow instanceof Classes.Workflow) {
235+
const yaml = workflow.serialize(/*'yaml' | 'json' */);
236236
}
237237
else {
238-
const json = Classes.Workflow.serialize(workflowDefinition, 'json');
238+
const json = Classes.Workflow.serialize(workflow, 'json');
239239
}
240240
```
241241
> [!NOTE]
@@ -247,13 +247,13 @@ Validation can be achieved in two ways: via the `validate` function or the insta
247247
```typescript
248248
import { Classes, validate } from '@serverlessworkflow/sdk';
249249

250-
const workflowDefinition = /* <Your preferred method> */;
250+
const workflow = /* <Your preferred method> */;
251251
try {
252-
if (workflowDefinition instanceof Classes.Workflow) {
253-
workflowDefinition.validate();
252+
if (workflow instanceof Classes.Workflow) {
253+
workflow.validate();
254254
}
255255
else {
256-
validate('Workflow', workflowDefinition);
256+
validate('Workflow', workflow);
257257
}
258258
}
259259
catch (ex) {
@@ -262,12 +262,14 @@ catch (ex) {
262262
```
263263

264264
#### Generate a directed graph
265-
A [directed graph](https://en.wikipedia.org/wiki/Directed_graph) of a workflow can be generated using the `buildGraph` function:
265+
A [directed graph](https://en.wikipedia.org/wiki/Directed_graph) of a workflow can be generated using the `buildGraph` function, or alternatives:
266+
- Workflow instance `.toGraph();`
267+
- Static `Classes.Workflow.toGraph(workflow)`
266268

267269
```typescript
268270
import { buildGraph } from '@serverlessworkflow/sdk';
269271

270-
const workflowDefinition = {
272+
const workflow = {
271273
document: {
272274
dsl: '1.0.0',
273275
name: 'using-plain-object',
@@ -284,7 +286,9 @@ const workflowDefinition = {
284286
},
285287
],
286288
};
287-
const graph = buildGraph(workflowDefinition);
289+
const graph = buildGraph(workflow);
290+
// const workflow = new Classes.Workflow({...}); const graph = workflow.toGraph();
291+
// const graph = Classes.Workflow.toGraph(workflow);
288292
/*{
289293
id: 'root',
290294
type: 'root',
@@ -298,12 +302,14 @@ const graph = buildGraph(workflowDefinition);
298302
```
299303

300304
#### Generate a MermaidJS flowchart
301-
Generating a [MermaidJS](https://mermaid.js.org/) flowchart can be achieved in two ways: using the `convertToMermaidCode` or the legacy `MermaidDiagram` class.
305+
Generating a [MermaidJS](https://mermaid.js.org/) flowchart can be achieved in two ways: using the `convertToMermaidCode`, the legacy `MermaidDiagram` class, or alternatives:
306+
- Workflow instance `.toMermaidCode();`
307+
- Static `Classes.Workflow.toMermaidCode(workflow)`
302308

303309
```typescript
304310
import { convertToMermaidCode, MermaidDiagram } from '@serverlessworkflow/sdk';
305311

306-
const workflowDefinition = {
312+
const workflow = {
307313
document: {
308314
dsl: '1.0.0',
309315
name: 'using-plain-object',
@@ -320,7 +326,10 @@ const workflowDefinition = {
320326
},
321327
],
322328
};
323-
const mermaidCode = convertToMermaidCode(workflowDefinition) /* or new MermaidDiagram(workflowDefinition).sourceCode() */;
329+
const mermaidCode = convertToMermaidCode(workflow) /* or */;
330+
// const mermaidCode = new MermaidDiagram(workflow).sourceCode();
331+
// const workflow = new Classes.Workflow({...}); const mermaidCode = workflow.toMermaidCode();
332+
// const mermaidCode = Classes.Workflow.toMermaidCode(workflow);
324333
/*
325334
flowchart TD
326335
root-entry-node(( ))

src/lib/generated/classes/workflow.ts

+40
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import { getLifecycleHooks } from '../../lifecycle-hooks';
3333
import { validate } from '../../validation';
3434
import { isObject } from '../../utils';
3535
import * as yaml from 'js-yaml';
36+
import { buildGraph, Graph } from '../../graph-builder';
37+
import { convertToMermaidCode } from '../../mermaid-converter';
3638

3739
/**
3840
* Represents the intersection between the Workflow class and type
@@ -112,6 +114,14 @@ export class Workflow extends ObjectHydrator<Specification.Workflow> {
112114
return yaml.dump(normalized);
113115
}
114116

117+
static toGraph(model: Partial<WorkflowIntersection>): Graph {
118+
return buildGraph(model as unknown as WorkflowIntersection);
119+
}
120+
121+
static toMermaidCode(model: Partial<WorkflowIntersection>): string {
122+
return convertToMermaidCode(model as unknown as WorkflowIntersection);
123+
}
124+
115125
/**
116126
* Serializes the workflow to YAML or JSON
117127
* @param format The format, 'yaml' or 'json', default is 'yaml'
@@ -121,6 +131,22 @@ export class Workflow extends ObjectHydrator<Specification.Workflow> {
121131
serialize(format: 'yaml' | 'json' = 'yaml', normalize: boolean = true): string {
122132
return Workflow.serialize(this as unknown as WorkflowIntersection, format, normalize);
123133
}
134+
135+
/**
136+
* Creates a directed graph representation of the workflow
137+
* @returns A directed graph of the workflow
138+
*/
139+
toGraph(): Graph {
140+
return Workflow.toGraph(this as unknown as WorkflowIntersection);
141+
}
142+
143+
/**
144+
* Generates the MermaidJS code corresponding to the workflow
145+
* @returns The MermaidJS code
146+
*/
147+
toMermaidCode(): string {
148+
return Workflow.toMermaidCode(this as unknown as WorkflowIntersection);
149+
}
124150
}
125151

126152
export const _Workflow = Workflow as WorkflowConstructor & {
@@ -139,4 +165,18 @@ export const _Workflow = Workflow as WorkflowConstructor & {
139165
* @returns A string representation of the workflow
140166
*/
141167
serialize(workflow: Partial<WorkflowIntersection>, format?: 'yaml' | 'json', normalize?: boolean): string;
168+
169+
/**
170+
* Creates a directed graph representation of the provided workflow
171+
* @param workflow The workflow to convert
172+
* @returns A directed graph of the provided workflow
173+
*/
174+
toGraph(workflow: Partial<WorkflowIntersection>): Graph;
175+
176+
/**
177+
* Generates the MermaidJS code corresponding to the provided workflow
178+
* @param workflow The workflow to convert
179+
* @returns The MermaidJS code
180+
*/
181+
toMermaidCode(workflow: Partial<WorkflowIntersection>): string;
142182
};

tests/graph/for.spec.ts

-40
This file was deleted.

0 commit comments

Comments
 (0)