Skip to content

Commit

Permalink
ddd
Browse files Browse the repository at this point in the history
  • Loading branch information
dontry committed Dec 2, 2024
1 parent eff24b0 commit c835f5a
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/components/SwimLaneDiagram/SwimLaneLayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,6 @@ const NodeComponents: Record<NodeType, any> = {
message: MessageNode,
ifelse: ConditionalNode,
endif: ConditionalNode,
loop: ConditionalNode,
};
</script>
23 changes: 23 additions & 0 deletions src/parser/SwimLane/Diagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IBlockStatement } from "./types";
import { AltStatement } from "./AltStatement";
import { MessageStatement } from "./MessageStatement";
import { AsyncMessageStatement } from "./AsyncMessageStatement";
import { LoopStatement } from "./LoopStatement";

// const statementContextMethods = [
// "message",
Expand Down Expand Up @@ -125,6 +126,28 @@ class SwimLaneCollector extends sequenceParserListener {
this.setCurrentBlockStatement(parentStatement);
}

enterLoop(ctx: any): void {
const currentStatement = new LoopStatement(
ctx,
this.swimLanes,
this.getCurrentBlockStatement(),
);
this.setCurrentBlockStatement(currentStatement);
}

exitLoop(): void {
const currentStatement = this.getCurrentBlockStatement();
if (!(currentStatement instanceof LoopStatement)) {
throw new Error("Current statement is not an LoopStatement");
}
currentStatement.setFinished();
const parentStatement = currentStatement.getParent();
if (!parentStatement) {
throw new Error("Parent statement is null");
}
this.setCurrentBlockStatement(parentStatement);
}

enterAsyncMessage(ctx: any): void {
const curBlockStatement = this.getCurrentBlockStatement();
new AsyncMessageStatement(ctx, this.swimLanes, curBlockStatement);
Expand Down
7 changes: 5 additions & 2 deletions src/parser/SwimLane/Edge.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { BaseNode } from "./Nodes";
import { JSONable } from "./types";
import { EdgeType, JSONable } from "./types";

export class Edge implements JSONable {
id: string;
source: BaseNode;
target: BaseNode;
type: EdgeType;

constructor(source: BaseNode, target: BaseNode) {
constructor(source: BaseNode, target: BaseNode, type?: EdgeType) {
this.id = `${source.id}-${target.id}`;
this.source = source;
this.target = target;
this.type = type ?? "normal";
}

toJSON() {
return {
id: this.id,
source: this.source.id,
target: this.target.id,
type: this.type,
};
}
}
61 changes: 61 additions & 0 deletions src/parser/SwimLane/LoopStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import ParserRuleContext from "antlr4/context/ParserRuleContext";
import { SwimLanes } from "./SwimLane";
import { BlockStatement } from "./Statement";
import { BaseNode, LoopNode } from "./Nodes";
import { Tile, IBlockStatement, IStatement } from "./types";
import { Edge } from "./Edge";

export class LoopStatement extends BlockStatement {
protected statements: IStatement[] = [];

constructor(
ctx: ParserRuleContext,
swimLanes: SwimLanes,
parentStatement: IBlockStatement | null,
) {
super(ctx, swimLanes, parentStatement);
}

appendChild(statement: IStatement): void {
this.statements.push(statement);
}

getTile(inboundNode: BaseNode): Tile {
return this.createBlock(inboundNode);
}

createBlock(inboundNode: BaseNode): Tile {
const loopNode = new LoopNode(
// @ts-ignore
this.ctx.parExpr?.().condition()?.getFormattedText(),
inboundNode?.swimLane,
inboundNode?.rank + 1,
);
loopNode.setPrevNode(inboundNode);
const edge = new Edge(inboundNode, loopNode);
this.addNode(loopNode);
this.addEdge(edge);

let prevNode: BaseNode | null = loopNode;
for (let i = 0; i < this.statements.length; i++) {
const statement = this.statements[i];
const tile = statement.getTile(prevNode);
this.addTile(tile);
prevNode = statement.getOutboundNode();
if (i === this.statements.length - 1) {
const outboundNode = prevNode;
if (outboundNode) {
const edge = new Edge(outboundNode, loopNode, "loop");
this.addEdge(edge);
}
}
}

this.connectNodes(inboundNode, loopNode);

return {
nodes: Array.from(this.nodes.values()),
edges: Array.from(this.edges.values()),
};
}
}
19 changes: 18 additions & 1 deletion src/parser/SwimLane/MessageStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,26 @@ export class MessageStatement extends BaseStatement {
: 0;

// TODO: optimize rank calculation
// const rank =
// this.parent && fromName === toName
// ? Math.max(this.parent.getMaxRank() + 1, fromSwimLaneMaxRank + 1)
// : this.parent.getMaxRank()
// let rank = 0;
// if (this.parent) {
// const parentMaxRank = this.parent.getMaxRank();
// rank =
// fromName === toName
// ? Math.max(parentMaxRank + 1, fromSwimLaneMaxRank + 1)
// : parentMaxRank;
// } else {
// rank =
// inboundNode?.rank && fromName !== toName
// ? Math.max(swimLane.maxRank + 1, fromSwimLaneMaxRank + 1)
// : swimLane.maxRank + 1;
// }
const rank =
inboundNode?.rank && fromName !== toName
? Math.max(swimLane.maxRank + 1, fromSwimLaneMaxRank + 1)
? Math.max(swimLane.maxRank + 1, fromSwimLaneMaxRank)
: swimLane.maxRank + 1;

const node = new MessageNode(message, swimLane, rank);
Expand Down
9 changes: 9 additions & 0 deletions src/parser/SwimLane/Nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,12 @@ export class EndIfNode extends BaseNode {
this.addToSwimLane(rank);
}
}

export class LoopNode extends BaseNode {
type: NodeType = "loop";

constructor(name: string, swimLane: SwimLane, rank: number) {
super(name, swimLane, rank);
this.addToSwimLane(rank);
}
}
18 changes: 17 additions & 1 deletion src/parser/SwimLane/Statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ export class BaseStatement implements IStatement {
}

export class BlockStatement extends BaseStatement implements IBlockStatement {
protected finished: boolean = false;

createBlock(node?: BaseNode | null): Tile {
throw new Error("Method not implemented.");
}
protected finished: boolean = false;

appendChild(statement: IStatement): void {
throw new Error("Method not implemented.");
Expand All @@ -101,6 +102,12 @@ export class BlockStatement extends BaseStatement implements IBlockStatement {
tile.nodes.forEach((node) => this.nodes.set(node.id, node));
tile.edges.forEach((edge) => this.edges.set(edge.id, edge));
}

getMaxRank(): number {
return Math.max(
...Array.from(this.nodes.values()).map((node) => node.rank),
);
}
}

export class RootStatement implements IBlockStatement {
Expand All @@ -115,6 +122,9 @@ export class RootStatement implements IBlockStatement {
this.ctx = ctx;
this.swimLanes = swimLanes;
}
getMaxRank(): number {
throw new Error("Method not implemented.");
}

getFirstSwimLane(): SwimLane {
return Array.from(this.swimLanes.lanes.values())[0];
Expand Down Expand Up @@ -163,6 +173,12 @@ export class RootStatement implements IBlockStatement {
};
}

getMaxRank(): number {
return Math.max(
...Array.from(this.nodes.values()).map((node) => node.rank),
);
}

getParent() {
return null;
}
Expand Down
15 changes: 10 additions & 5 deletions src/parser/SwimLane/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Edge } from "./Edge";
import { BaseNode } from "./Nodes";

export type NodeType = "message" | "ifelse" | "endif";
export type NodeType = "message" | "ifelse" | "endif" | "loop";
export type EdgeType = "normal" | "loop";

export interface JSONable {
toJSON(): Record<string, any>;
Expand All @@ -25,6 +26,7 @@ export interface IStatement {
export interface IBlockStatement extends IStatement {
createBlock(node?: BaseNode | null): Tile;
appendChild(statement: IStatement): void;
getMaxRank(): number;
setFinished(): void;
isFinished(): boolean;
}
Expand All @@ -36,19 +38,22 @@ export function isBlockStatement(
}

export type SwimLaneId = string;
export type NodeId = string;
export type EdgeId = string;

export interface NodeModel {
id: string;
id: NodeId;
name: string;
type: NodeType;
rank: number;
swimLane: SwimLaneId;
}

export interface EdgeModel {
id: string;
source: string;
target: string;
id: EdgeId;
source: NodeId;
target: NodeId;
type: EdgeType;
}

export interface SwimLaneDiagramModel {
Expand Down

0 comments on commit c835f5a

Please sign in to comment.