import { populateCommonDb } from "./chunk-6ZKBGPIT.mjs"; import { parse } from "./chunk-2ENXBMWA.mjs"; import "./chunk-HQDACWF7.mjs"; import "./chunk-CYW2HGLJ.mjs"; import "./chunk-CT5Q72BK.mjs"; import "./chunk-3O5MS6M4.mjs"; import "./chunk-D6UAH5RW.mjs"; import "./chunk-LJRZYMMA.mjs"; import "./chunk-NZTEHIZO.mjs"; import "./chunk-WM6EUEOH.mjs"; import "./chunk-D6MTONMS.mjs"; import { calculateTextDimensions, cleanAndMerge, wrapLabel } from "./chunk-BSZA5ISF.mjs"; import "./chunk-7TFACZ55.mjs"; import { clear, defaultConfig_default, getAccDescription, getAccTitle, getConfig, getConfig2, getDiagramTitle, sanitizeText, setAccDescription, setAccTitle, setDiagramTitle, setupGraphViewbox2 as setupGraphViewbox } from "./chunk-Q52JI7PB.mjs"; import { log, select_default } from "./chunk-V7P66DNM.mjs"; import "./chunk-BBDM4ZFP.mjs"; import { isEmResetFrame } from "./chunk-NW2N4LI3.mjs"; import { __name } from "./chunk-PTVI3W5X.mjs"; // src/diagrams/eventmodeling/types.ts var PositionFrameKind = "position frame"; var FramePositionedKind = "frame positioned"; var PositionRelationKind = "position relation"; var RelationPositionedKind = "relation positioned"; // src/diagrams/eventmodeling/db.ts var setOptions = /* @__PURE__ */ __name(function(_rawOptString) { log.debug("options str", _rawOptString); }, "setOptions"); var getOptions = /* @__PURE__ */ __name(function() { return {}; }, "getOptions"); var clear2 = /* @__PURE__ */ __name(function() { reset(); clear(); }, "clear"); function reset() { store = {}; } __name(reset, "reset"); var DEFAULT_EVENTMODELING_CONFIG = defaultConfig_default.eventmodeling; var getConfig3 = /* @__PURE__ */ __name(() => { const config = cleanAndMerge({ ...DEFAULT_EVENTMODELING_CONFIG, ...getConfig().eventmodeling }); return config; }, "getConfig"); var store = {}; function getState() { let state = initial; const { ast } = store; const diagramProps2 = getDiagramProps(); if (!ast) { throw new Error("No data for EventModel"); } ast.frames.forEach((frame, index) => { const textProps = calculateTextProps(frame, ast.dataEntities, diagramProps2); state = dispatch(state, { $kind: PositionFrameKind, index, frame, textProps }); let sourceFrames = void 0; if (hasSourceFrame(frame)) { log.debug(`source frame`, frame.sourceFrames); sourceFrames = ast.frames.filter((currentFrame) => { return frame.sourceFrames.some((sf) => sf.$refText === currentFrame.name); }); sourceFrames.forEach((sourceFrame) => { state = dispatch(state, { $kind: PositionRelationKind, index, frame, sourceFrame }); }); } else { state = dispatch(state, { $kind: PositionRelationKind, index, frame }); } }); state = { ...state, sortedSwimlanesArray: sortedSwimlanesArray(state.swimlanes) }; return state; } __name(getState, "getState"); function setAst(ast) { store.ast = ast; } __name(setAst, "setAst"); var diagramProps = { swimlaneMinHeight: 70, swimlanePadding: 15, swimlaneGap: 10, boxPadding: 10, boxOverlap: 90, boxDefaultY: 0, boxMinWidth: 80, boxMaxWidth: 450, boxMinHeight: 80, boxMaxHeight: 750, contentStartX: 250, textMaxWidth: 450 - 2 * 10, boxTextFontWeight: "bold", boxTextPadding: 10, swimlaneTextFontWeight: "bold", labelUiAutomation: "UI/Automation", labelUiAutomationPrefix: "UI/A: ", labelCommandReadModel: "Command/Read Model", labelCommandReadModelPrefix: "C/RM: ", labelEvents: "Events", labelEventsPrefix: "Stream: " }; function getDiagramProps() { return diagramProps; } __name(getDiagramProps, "getDiagramProps"); var initial = { boxes: [], swimlanes: {}, relations: [], maxR: 0, sortedSwimlanesArray: [] }; function extractNamespace(entityIdentifier) { const spl = entityIdentifier.split("."); if (spl.length === 2) { return spl[0]; } return void 0; } __name(extractNamespace, "extractNamespace"); function extractName(entityIdentifier) { const spl = entityIdentifier.split("."); if (spl.length === 2) { return spl[1]; } return entityIdentifier; } __name(extractName, "extractName"); function findSwimlaneByNamespace(swimlanes, namespace) { if (!namespace || namespace.length === 0) { return void 0; } return Object.values(swimlanes).find((swimlane) => swimlane.namespace === namespace); } __name(findSwimlaneByNamespace, "findSwimlaneByNamespace"); function findNextAvailableIndex(swimlanes, boundaryMin, boundaryMax) { return Math.max( boundaryMin, ...Object.keys(swimlanes).filter((key) => { const index = Number.parseInt(key); return index > boundaryMin && index < boundaryMax; }).map((key) => Number.parseInt(key)) ) + 1; } __name(findNextAvailableIndex, "findNextAvailableIndex"); function calculateSwimlaneProps(frame, swimlanes) { const namespace = extractNamespace(frame.entityIdentifier); const sw = findSwimlaneByNamespace(swimlanes, namespace); switch (frame.modelEntityType) { case "ui": case "pcr": case "processor": if (sw) { return { index: sw.index, label: sw.namespace || diagramProps.labelUiAutomation }; } else if (namespace) { return { index: findNextAvailableIndex(swimlanes, 0, 100), label: diagramProps.labelUiAutomationPrefix + namespace }; } return { index: 0, label: diagramProps.labelUiAutomation }; case "rmo": case "readmodel": case "cmd": case "command": if (sw) { return { index: sw.index, label: sw.namespace || diagramProps.labelCommandReadModel }; } else if (namespace) { return { index: findNextAvailableIndex(swimlanes, 100, 200), label: diagramProps.labelCommandReadModelPrefix + namespace }; } return { index: 100, label: diagramProps.labelCommandReadModel }; case "evt": case "event": default: if (sw) { return { index: sw.index, label: sw.namespace || diagramProps.labelEvents }; } else if (namespace) { return { index: findNextAvailableIndex(swimlanes, 200, 300), label: diagramProps.labelEventsPrefix + namespace }; } return { index: 200, label: diagramProps.labelEvents }; } } __name(calculateSwimlaneProps, "calculateSwimlaneProps"); function calculateEntityVisualProps(frame) { const { themeVariables } = getConfig(); switch (frame.modelEntityType) { case "ui": return { fill: themeVariables.emUiFill ?? "white", stroke: themeVariables.emUiStroke ?? "#dbdada" }; case "pcr": case "processor": return { fill: themeVariables.emProcessorFill ?? "#edb3f6", stroke: themeVariables.emProcessorStroke ?? "#b88cbf" }; case "rmo": case "readmodel": return { fill: themeVariables.emReadModelFill ?? "#d3f1a2", stroke: themeVariables.emReadModelStroke ?? "#a3b732" }; case "cmd": case "command": return { fill: themeVariables.emCommandFill ?? "#bcd6fe", stroke: themeVariables.emCommandStroke ?? "#679ac3" }; case "evt": case "event": return { fill: themeVariables.emEventFill ?? "#ffb778", stroke: themeVariables.emEventStroke ?? "#c19a0f" }; default: return { fill: "red", stroke: "black" }; } } __name(calculateEntityVisualProps, "calculateEntityVisualProps"); function calculateTextProps(frame, dataEntities, diagramProps2) { const config = getConfig(); const name = sanitizeText(extractName(frame.entityIdentifier) ?? "", config); let toHtml; const wrapLabelConfig = { fontSize: 16, fontWeight: 700, fontFamily: '"trebuchet ms", verdana, arial, sans-serif', joinWith: "
" }; const wrappedName = wrapLabel(name, diagramProps2.textMaxWidth, wrapLabelConfig); let content = `${wrappedName}`; if (frame.dataInlineValue) { toHtml = frame.dataInlineValue; toHtml = toHtml.substring(toHtml.indexOf("{") + 1); toHtml = toHtml.substring(0, toHtml.lastIndexOf("}") - 1); toHtml = sanitizeText(toHtml, config); toHtml = wrapLabel(toHtml, diagramProps2.textMaxWidth, wrapLabelConfig); toHtml = toHtml.replaceAll(" ", " "); } if (frame.dataReference) { const dataEntity = dataEntities.find( (dataEntity2) => dataEntity2.name === frame.dataReference?.$refText ); if (dataEntity) { toHtml = dataEntity.dataBlockValue; toHtml = toHtml.substring(toHtml.indexOf("{\n") + 2); toHtml = toHtml.substring(0, toHtml.lastIndexOf("}") - 1); toHtml = sanitizeText(toHtml, config); toHtml = wrapLabel(toHtml, diagramProps2.textMaxWidth, wrapLabelConfig); toHtml = toHtml.replaceAll(" ", " "); toHtml += `
`; } } const hasRenderedData = toHtml !== void 0; if (hasRenderedData) { content += `

${toHtml}`; } const textDimensionConfig = { fontSize: wrapLabelConfig.fontSize, fontWeight: wrapLabelConfig.fontWeight, fontFamily: wrapLabelConfig.fontFamily }; const dimensions = calculateTextDimensions(content, textDimensionConfig); const calculatedWidthFix = hasRenderedData ? dimensions.width / 3 : dimensions.width; const props = { content, width: calculatedWidthFix, height: dimensions.height }; log.debug(`[${frame.name}] ${frame.entityIdentifier} text`, props); return props; } __name(calculateTextProps, "calculateTextProps"); function decidePositionFrame(state, _command) { const command = _command; const visual = calculateEntityVisualProps(command.frame); const dimension = { width: command.textProps.width + 2 * diagramProps.boxTextPadding, height: command.textProps.height + 2 * diagramProps.boxTextPadding }; const event = { $kind: FramePositionedKind, frame: command.frame, index: command.index, visual, dimension, textProps: command.textProps }; return [event]; } __name(decidePositionFrame, "decidePositionFrame"); function calculateX(swimlane, previousSwimlane, lastBox) { if (previousSwimlane === void 0) { return diagramProps.contentStartX; } if (previousSwimlane.index === swimlane.index && swimlane.r) { return swimlane.r + diagramProps.boxPadding; } if (lastBox === void 0) { return diagramProps.contentStartX; } return lastBox.r - diagramProps.boxOverlap + diagramProps.boxPadding; } __name(calculateX, "calculateX"); function calculateMaxRight(swimlanes, swimlaneR) { const rs = [...swimlanes.map((s) => s.r), swimlaneR]; return Math.max(...rs); } __name(calculateMaxRight, "calculateMaxRight"); function sortedSwimlanesArray(swimlanes) { return Object.values(swimlanes).sort((a, b) => a.index - b.index); } __name(sortedSwimlanesArray, "sortedSwimlanesArray"); function evolveFramePositioned(state, _event) { const event = _event; const swimlaneProps = calculateSwimlaneProps(event.frame, state.swimlanes); let swimlane; if (swimlaneProps.index in state.swimlanes) { swimlane = state.swimlanes[swimlaneProps.index]; } else { swimlane = { index: swimlaneProps.index, label: swimlaneProps.label, r: 0, y: swimlaneProps.index * diagramProps.swimlaneMinHeight + diagramProps.swimlaneGap, height: diagramProps.swimlaneMinHeight, maxHeight: diagramProps.swimlaneMinHeight }; } const lastBox = state.boxes.length > 0 ? state.boxes[state.boxes.length - 1] : void 0; const previousSwimlane = state.previousSwimlaneNumber !== void 0 ? state.swimlanes[state.previousSwimlaneNumber] : void 0; const dimension = { width: Math.max( diagramProps.boxMinWidth, Math.min(diagramProps.boxMaxWidth, event.dimension.width) ) + 2 * diagramProps.boxPadding, height: Math.max( diagramProps.boxMinHeight, Math.min(diagramProps.boxMaxHeight, event.dimension.height) ) + 2 * diagramProps.boxPadding }; const x = calculateX(swimlane, previousSwimlane, lastBox); const r = x + dimension.width + diagramProps.boxPadding; const maxR = calculateMaxRight(Object.values(state.swimlanes), r); swimlane.r = x + dimension.width; swimlane.maxHeight = Math.max(swimlane.maxHeight, dimension.height); swimlane.height = Math.max(diagramProps.swimlaneMinHeight, swimlane.maxHeight) + 2 * diagramProps.swimlanePadding; const box = { x, y: diagramProps.swimlanePadding + swimlane.y, // y: diagramProps.swimlanePadding + (swimlane.y || diagramProps.boxDefaultY), r, dimension, leftSibling: false, swimlane, visual: event.visual, text: event.textProps.content, frame: event.frame, index: event.index }; const newState = { ...state, boxes: [...state.boxes, box], swimlanes: { ...state.swimlanes, [`${swimlane.index}`]: swimlane }, previousSwimlaneNumber: swimlaneProps.index, previousFrame: event.frame, maxR }; const swimlanes = sortedSwimlanesArray(newState.swimlanes); if (swimlanes.length > 0) { swimlanes[0].y = 0; } for (let i = 1; i < swimlanes.length; i++) { const sw = swimlanes[i]; const prevSw = swimlanes[i - 1]; sw.y = prevSw.y + prevSw.height + diagramProps.swimlaneGap; } return newState; } __name(evolveFramePositioned, "evolveFramePositioned"); function isFirstFrame(index, frame) { if (index === 0 && frame.sourceFrames.length === 0) { return true; } return false; } __name(isFirstFrame, "isFirstFrame"); function hasSourceFrame(frame) { return frame.sourceFrames !== void 0 && frame.sourceFrames !== null && frame.sourceFrames.length > 0; } __name(hasSourceFrame, "hasSourceFrame"); function findBoxByFrame(boxes, frame) { if (frame === void 0 || frame === null) { return void 0; } return boxes.find((box) => box.frame.name === frame.name); } __name(findBoxByFrame, "findBoxByFrame"); function findBoxByLineIndex(boxes, targetSwimlane, lineIndex) { if (lineIndex < 0) { return void 0; } for (let i = lineIndex; i >= 0; i--) { const box = boxes[i]; if (box.swimlane.index !== targetSwimlane) { return box; } } return void 0; } __name(findBoxByLineIndex, "findBoxByLineIndex"); function decidePositionRelation(state, _command) { const command = _command; if (isEmResetFrame(command.frame) || isFirstFrame(command.index, command.frame)) { return []; } const targetBox = findBoxByFrame(state.boxes, command.frame); if (targetBox === void 0) { throw new Error(`Target box not found for frame ${command.frame.name}`); } let sourceBox; if (command.sourceFrame) { sourceBox = findBoxByFrame(state.boxes, command.sourceFrame); } else { sourceBox = findBoxByLineIndex(state.boxes, targetBox.swimlane.index, command.index - 1); } if (sourceBox === void 0) { return []; } const event = { $kind: RelationPositionedKind, frame: command.frame, index: command.index, sourceBox, targetBox }; return [event]; } __name(decidePositionRelation, "decidePositionRelation"); function evolveRelationPositioned(state, _event) { const event = _event; const relation = { visual: { fill: "none", stroke: "#000" }, source: { x: event.sourceBox.x, y: event.sourceBox.y }, target: { x: event.targetBox.x, y: event.targetBox.y }, sourceBox: event.sourceBox, targetBox: event.targetBox }; const newState = { ...state, relations: [...state.relations, relation] }; return newState; } __name(evolveRelationPositioned, "evolveRelationPositioned"); var deciders = { [PositionFrameKind]: decidePositionFrame, [PositionRelationKind]: decidePositionRelation }; var evolvers = { [FramePositionedKind]: evolveFramePositioned, [RelationPositionedKind]: evolveRelationPositioned }; function decide(state, command) { const fn = deciders[command.$kind]; if (fn === void 0 || fn === null) { return []; } const events = fn(state, command); log.debug(`decided events`, events); return events; } __name(decide, "decide"); function evolve(state, events) { const newState = events.reduce((previousState, event) => { const fn = evolvers[event.$kind]; if (fn === void 0 || fn === null) { return previousState; } return fn(previousState, event); }, state); log.debug(`evolve events`, { state, newState, events }); return newState; } __name(evolve, "evolve"); function dispatch(state, command) { const events = decide(state, command); const newState = evolve(state, events); return newState; } __name(dispatch, "dispatch"); var db = { getConfig: getConfig3, setOptions, getOptions, clear: clear2, setAccTitle, getAccTitle, getAccDescription, setAccDescription, setDiagramTitle, getDiagramTitle, setAst, getDiagramProps, getState }; // src/diagrams/eventmodeling/parser.ts var parser = { parse: /* @__PURE__ */ __name(async (input) => { const ast = await parse("eventmodeling", input); log.debug(ast); db.setAst(ast); populateCommonDb(ast, db); }, "parse") }; if (void 0) { const { it, expect, describe } = void 0; describe("EventModeling Parser", () => { it("should parse simple model", () => { const result = parser.parse(`eventmodeling tf 01 evt Start `); expect(result !== void 0); }); }); } // src/diagrams/eventmodeling/renderer.ts var DEFAULT_CONFIG = getConfig2(); var DEFAULT_EVENTMODELING_CONFIG2 = DEFAULT_CONFIG?.eventmodeling; function renderD3Box(diagram2, diagramProps2) { return (box) => { const y = box.swimlane.y + diagramProps2.swimlanePadding; const g = diagram2.append("g").attr("class", "em-box"); g.append("rect").attr("x", box.x).attr("y", y).attr("rx", "3").attr("width", box.dimension.width).attr("height", box.dimension.height).attr("stroke", box.visual.stroke).attr("fill", box.visual.fill); const f = g.append("foreignObject").attr("x", box.x + diagramProps2.boxPadding).attr("y", y + 10).attr("width", box.dimension.width - 2 * diagramProps2.boxPadding).attr("height", box.dimension.height - 2 * diagramProps2.boxPadding); const text = f.append("xhtml:div").style("display", "table").style("height", "100%").style("width", "100%"); text.append("span").style("display", "table-cell").style("text-align", "center").style("vertical-align", "middle").html(box.text); }; } __name(renderD3Box, "renderD3Box"); function dirUpwards(sourceY, targetY) { return sourceY > targetY; } __name(dirUpwards, "dirUpwards"); function renderD3Relation(diagram2, diagramProps2, arrowheadId, themeVariables) { return (relation) => { const sourceBoxY = relation.sourceBox.swimlane.y + diagramProps2.swimlanePadding; const targetBoxY = relation.targetBox.swimlane.y + diagramProps2.swimlanePadding; const upwards = dirUpwards(sourceBoxY, targetBoxY); const sourceX = relation.sourceBox.x + relation.sourceBox.dimension.width * 2 / 3; const targetX = relation.targetBox.x + relation.targetBox.dimension.width / 3; let sourceY; let targetY; log.debug(`rendering relation up=${upwards} for `, { sourceBox: relation.sourceBox, targetBox: relation.targetBox }); if (upwards) { sourceY = sourceBoxY; targetY = targetBoxY + relation.targetBox.dimension.height; } else { sourceY = sourceBoxY + relation.sourceBox.dimension.height; targetY = targetBoxY; } const relationStroke = themeVariables.emRelationStroke ?? relation.visual.stroke; diagram2.append("path").attr("class", "em-relation").attr("fill", relation.visual.fill).attr("stroke", relationStroke).attr("stroke-width", "1").attr("marker-end", `url(#${arrowheadId})`).attr("d", `M${sourceX} ${sourceY} L${targetX} ${targetY}`); }; } __name(renderD3Relation, "renderD3Relation"); function renderD3Swimlane(diagram2, maxR, diagramProps2, themeVariables) { return (swimlane) => { const g = diagram2.append("g").attr("class", "em-swimlane"); const oddBackground = themeVariables.emSwimlaneBackgroundOdd ?? "rgb(250,250,250)"; const backgroundStroke = themeVariables.emSwimlaneBackgroundStroke ?? "rgb(240,240,240)"; g.append("rect").attr("x", 0).attr("y", swimlane.y).attr("rx", "3").attr("width", maxR + diagramProps2.swimlanePadding).attr("height", swimlane.height).attr("fill", oddBackground).attr("stroke", backgroundStroke); g.append("text").attr("font-weight", diagramProps2.swimlaneTextFontWeight).attr("x", 30).attr("y", swimlane.y + 30).text(swimlane.label); }; } __name(renderD3Swimlane, "renderD3Swimlane"); var draw = /* @__PURE__ */ __name(function(txt, id, ver, diagObj) { log.debug("in eventmodeling renderer", txt + "\n", "id:", id, ver); if (!DEFAULT_EVENTMODELING_CONFIG2) { throw new Error("EventModeling config not found"); } const db2 = diagObj.db; const { themeVariables, eventmodeling: config } = getConfig2(); const diagram2 = select_default(`[id="${id}"]`); const diagramProps2 = db2.getDiagramProps(); const state = db2.getState(); const arrowheadId = `em-arrowhead-${id}`; const arrowheadColor = themeVariables.emArrowhead ?? "#000000"; state.sortedSwimlanesArray.forEach( renderD3Swimlane(diagram2, state.maxR, diagramProps2, themeVariables) ); state.boxes.forEach(renderD3Box(diagram2, diagramProps2)); state.relations.forEach(renderD3Relation(diagram2, diagramProps2, arrowheadId, themeVariables)); const marker = diagram2.append("defs").append("marker").attr("id", arrowheadId).attr("markerWidth", "10").attr("markerHeight", "7").attr("refX", "10").attr("refY", "3.5").attr("orient", "auto"); marker.append("polygon").attr("points", "0 0, 10 3.5, 0 7").attr("fill", arrowheadColor); setupGraphViewbox(void 0, diagram2, config?.padding ?? 30, config?.useMaxWidth); }, "draw"); var renderer_default = { draw }; // src/diagrams/eventmodeling/styles.js var getStyles = /* @__PURE__ */ __name((_options) => ``, "getStyles"); var styles_default = getStyles; // src/diagrams/eventmodeling/diagram.ts var diagram = { parser, db, renderer: renderer_default, styles: styles_default }; export { diagram };