Skip to content

Commit 7c99072

Browse files
authored
Merge pull request #658 from jvalue/graph-style
Graph style
2 parents 5db99e8 + 3658d79 commit 7c99072

File tree

7 files changed

+267
-24
lines changed

7 files changed

+267
-24
lines changed

libs/execution/src/lib/blocks/block-executor.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ import { isBlockTargetedForDebugLogging } from '../debugging/debug-configuration
1111
import { DebugLogVisitor } from '../debugging/debug-log-visitor';
1212
import { type ExecutionContext } from '../execution-context';
1313
import { type IOTypeImplementation } from '../types/io-types/io-type-implementation';
14-
import { Edge, type Graph, type Id, Node } from '../util/mermaid-util';
14+
import {
15+
ClassAssignment,
16+
Edge,
17+
type Graph,
18+
type Id,
19+
Node,
20+
} from '../util/mermaid-util';
1521

1622
import * as R from './execution-result';
1723

@@ -88,9 +94,13 @@ export abstract class AbstractBlockExecutor<I extends IOType, O extends IOType>
8894
const node = new Node(context.getCurrentNode().name, '[ ]');
8995
graph.addNode(node);
9096

97+
graph.addClassAssignment(new ClassAssignment(node.id, 'block'));
98+
graph.addClassAssignment(new ClassAssignment(node.id, node.text));
99+
91100
for (const parent of parents) {
92101
const edge = new Edge(parent, node.id, this.inputType, '-->');
93102
graph.addEdge(edge);
103+
graph.addClassAssignment(new ClassAssignment(edge.id, 'edge'));
94104
}
95105

96106
return node.id;

libs/execution/src/lib/blocks/composite-block-executor.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323

2424
import { type ExecutionContext } from '../execution-context';
2525
import { type IOTypeImplementation } from '../types';
26-
import { Edge, type Graph, type Id } from '../util';
26+
import { ClassAssignment, Edge, type Graph, type Id } from '../util';
2727

2828
import { executeBlocks, executionGraph } from './block-execution-util';
2929
import { AbstractBlockExecutor, type BlockExecutor } from './block-executor';
@@ -65,9 +65,18 @@ export function createCompositeBlockExecutor(
6565
const subgraph = executionGraph(context, blockTypeReference);
6666
graph.addSubgraph(subgraph);
6767

68+
graph.addClassAssignment(
69+
new ClassAssignment(subgraph.id, 'composite-block'),
70+
);
71+
assert(subgraph.title !== undefined);
72+
graph.addClassAssignment(
73+
new ClassAssignment(subgraph.id, subgraph.title),
74+
);
75+
6876
for (const parent of parents) {
6977
const edge = new Edge(parent, subgraph.id, this.inputType, '-->');
7078
graph.addEdge(edge);
79+
graph.addClassAssignment(new ClassAssignment(edge.id, 'edge'));
7180
}
7281

7382
return subgraph.id;

libs/execution/src/lib/util/mermaid-util.ts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import assert from 'assert';
77

88
import { type BlockDefinition } from '@jvalue/jayvee-language-server';
9+
import { stringify } from 'yaml';
910

1011
import { type ExecutionContext } from '../execution-context';
1112

@@ -119,26 +120,76 @@ export class ClassAssignment {
119120
}
120121
}
121122

123+
export interface ThemeVariables {
124+
darkMode: boolean;
125+
background: string;
126+
fontFamily: string;
127+
fontSize: string;
128+
primaryColor: string;
129+
primaryTextColor: string;
130+
primaryBorderColor: string;
131+
secondaryColor: string;
132+
secondaryTextColor: string;
133+
secondaryBorderColor: string;
134+
tertiaryColor: string;
135+
tertiaryTextColor: string;
136+
tertiaryBorderColor: string;
137+
noteBkgColor: string;
138+
noteTextColor: string;
139+
noteBorderColor: string;
140+
lineColor: string;
141+
textColor: string;
142+
mainBkg: string;
143+
errorBkgColor: string;
144+
errorTextColor: string;
145+
146+
nodeBorder: string;
147+
clusterBkg: string;
148+
clusterBorder: string;
149+
defaultLinkColor: string;
150+
titleColor: string;
151+
edgeLabelBackground: string;
152+
nodeTextColor: string;
153+
}
154+
155+
export interface ElkLayoutConfig {
156+
mergeEdges: boolean;
157+
nodePlacementStrategy:
158+
| 'BRANDES_KOEPF'
159+
| 'SIMPLE'
160+
| 'NETWORK_SIMPLEX'
161+
| 'LINEAR_SEGMENTS';
162+
}
163+
164+
export interface GraphConfiguration {
165+
look: 'classic' | 'handDrawn';
166+
theme: 'default' | 'neutral' | 'dark' | 'forest' | 'plain';
167+
themeVariables: Partial<ThemeVariables>;
168+
layout: 'dagre' | 'elk';
169+
elk: Partial<ElkLayoutConfig>;
170+
}
171+
122172
export type GraphDirection = 'TB' | 'BT' | 'RL' | 'LR';
173+
123174
export class Graph {
124175
private readonly _id: Id = getId();
125176
private direction: GraphDirection = 'TB';
126177
private nodes = new Map<Id, Node>();
127178

128179
private edges = new Map<Id, Edge>();
129-
private edgeAttributes: { id: Id; attributes: string[] }[] = [];
180+
private edgeAttributes: EdgeAttribute[] = [];
130181

131182
private subgraphs = new Map<Id, Graph>();
132183

133-
private classDefinitions: {
134-
class: string;
135-
propertiesAndValues: string[];
136-
}[] = [];
137-
private classAssignments: { id: Id; class: string }[] = [];
184+
private classDefinitions: ClassDefinition[] = [];
185+
private classAssignments: ClassAssignment[] = [];
138186

139187
private blocks = new Map<BlockDefinition, Id>();
140188

141-
constructor(public title?: string) {}
189+
constructor(
190+
public title?: string,
191+
public configuration?: Partial<GraphConfiguration>,
192+
) {}
142193

143194
get id(): Id {
144195
return this._id;
@@ -188,6 +239,14 @@ export class Graph {
188239
this.edges.set(edge.id, edge);
189240
}
190241

242+
public addClassAssignment(assignment: ClassAssignment) {
243+
this.classAssignments.push(assignment);
244+
}
245+
246+
public addClassDefinition(classDefinition: ClassDefinition) {
247+
this.classDefinitions.push(classDefinition);
248+
}
249+
191250
public toSubgraph(indents: number): string {
192251
const title = this.title !== undefined ? ` [${this.title}]` : '';
193252
return `subgraph ${this.id}${title}
@@ -197,9 +256,15 @@ ${indents > 0 ? '\t'.repeat(indents - 1) : ''}end`;
197256
}
198257

199258
toString(): string {
200-
const title = this.title !== undefined ? `\ntitle: ${this.title}` : '';
201-
return `---${title}
202-
---
259+
return `---
260+
${
261+
this.title !== undefined || this.configuration !== undefined
262+
? stringify({
263+
title: this.title,
264+
config: this.configuration,
265+
})
266+
: '\n'
267+
}---
203268
flowchart ${this.direction}
204269
${this.content(1)}`;
205270
}

libs/interpreter-lib/src/interpreter.spec.ts

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,25 @@ flowchart TB
307307
\tc f@-->|TextFile| e
308308
\te h@-->|Sheet| g
309309
\tg j@-->|Sheet| i
310-
\ti l@-->|Table| k`);
310+
\ti l@-->|Table| k
311+
312+
\tclass b block
313+
\tclass b CarsExtractor
314+
\tclass c block
315+
\tclass c CarsTextFileInterpreter
316+
\tclass d edge
317+
\tclass e block
318+
\tclass e CarsCSVInterpreter
319+
\tclass f edge
320+
\tclass g block
321+
\tclass g NameHeaderWriter
322+
\tclass h edge
323+
\tclass i block
324+
\tclass i CarsTableInterpreter
325+
\tclass j edge
326+
\tclass k block
327+
\tclass k CarsLoader
328+
\tclass l edge`);
311329
});
312330
it('should graph the composite-blocks example', async () => {
313331
const assetPath =
@@ -356,7 +374,28 @@ flowchart TB
356374
357375
\t\to q@-->|File| p
358376
\t\tp s@-->|TextFile| r
359-
\tend`);
377+
378+
\t\tclass o block
379+
\t\tclass o FileExtractor
380+
\t\tclass p block
381+
\t\tclass p FileTextInterpreter
382+
\t\tclass q edge
383+
\t\tclass r block
384+
\t\tclass r FileCSVInterpreter
385+
\t\tclass s edge
386+
\tend
387+
388+
\tclass n composite-block
389+
\tclass n CSVExtractor
390+
\tclass t block
391+
\tclass t CarsTableInterpreter
392+
\tclass u edge
393+
\tclass v block
394+
\tclass v CarsTableTransformer
395+
\tclass w edge
396+
\tclass x block
397+
\tclass x CarsLoader
398+
\tclass y edge`);
360399
});
361400
it('should graph models with two contained pipelines', async () => {
362401
const assetPath =
@@ -386,6 +425,7 @@ flowchart TB
386425
assert(graph !== 'No pipelines to graph');
387426

388427
expect(graph.toString()).toBe(`---
428+
389429
---
390430
flowchart TB
391431
\tsubgraph ba [CarsPipeline]
@@ -402,6 +442,24 @@ flowchart TB
402442
\t\tbe bh@-->|Sheet| bg
403443
\t\tbg bj@-->|Sheet| bi
404444
\t\tbi bl@-->|Table| bk
445+
446+
\t\tclass bb block
447+
\t\tclass bb CarsExtractor
448+
\t\tclass bc block
449+
\t\tclass bc CarsTextFileInterpreter
450+
\t\tclass bd edge
451+
\t\tclass be block
452+
\t\tclass be CarsCSVInterpreter
453+
\t\tclass bf edge
454+
\t\tclass bg block
455+
\t\tclass bg NameHeaderWriter
456+
\t\tclass bh edge
457+
\t\tclass bi block
458+
\t\tclass bi CarsTableInterpreter
459+
\t\tclass bj edge
460+
\t\tclass bk block
461+
\t\tclass bk CarsLoader
462+
\t\tclass bl edge
405463
\tend
406464
\tsubgraph bm [ElectricVehiclesPipeline]
407465
\t\tdirection TB
@@ -417,7 +475,30 @@ flowchart TB
417475
\t\tbq bt@-->|Sheet| bs
418476
\t\tbs bv@-->|Table| bu
419477
\t\tbu bx@-->|Table| bw
420-
\tend`);
478+
479+
\t\tclass bn block
480+
\t\tclass bn ElectricVehiclesHttpExtractor
481+
\t\tclass bo block
482+
\t\tclass bo ElectricVehiclesTextFileInterpreter
483+
\t\tclass bp edge
484+
\t\tclass bq block
485+
\t\tclass bq ElectricVehiclesCSVInterpreter
486+
\t\tclass br edge
487+
\t\tclass bs block
488+
\t\tclass bs ElectricVehiclesTableInterpreter
489+
\t\tclass bt edge
490+
\t\tclass bu block
491+
\t\tclass bu ElectricRangeTransformer
492+
\t\tclass bv edge
493+
\t\tclass bw block
494+
\t\tclass bw ElectricVehiclesSQLiteLoader
495+
\t\tclass bx edge
496+
\tend
497+
498+
\tclass ba pipeline
499+
\tclass ba pipeline
500+
\tclass bm pipeline
501+
\tclass bm pipeline`);
421502
});
422503
});
423504
});

libs/interpreter-lib/src/interpreter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { strict as assert } from 'assert';
77
import path from 'node:path';
88

99
import {
10+
ClassAssignment,
1011
type DebugGranularity,
1112
type DebugTargets,
1213
DefaultConstraintExtension,
@@ -395,6 +396,9 @@ export class DefaultJayveeInterpreter implements JayveeInterpreter {
395396
program.hooks,
396397
);
397398
graph.addSubgraph(subgraph);
399+
graph.addClassAssignment(new ClassAssignment(subgraph.id, 'pipeline'));
400+
if (subgraph.title !== undefined)
401+
graph.addClassAssignment(new ClassAssignment(subgraph.id, 'pipeline'));
398402
}
399403

400404
return graph;

0 commit comments

Comments
 (0)