From 61a73ca389edb5aee67b5b64102c22a61b974eaa Mon Sep 17 00:00:00 2001 From: sam schick Date: Sat, 14 Sep 2024 23:27:01 +0000 Subject: [PATCH 1/3] eventModel parser first pass --- packages/parser/langium-config.json | 5 +++ .../language/eventModel/eventModel.langium | 45 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 packages/parser/src/language/eventModel/eventModel.langium diff --git a/packages/parser/langium-config.json b/packages/parser/langium-config.json index bf64493ad8..9a3f28d3c1 100644 --- a/packages/parser/langium-config.json +++ b/packages/parser/langium-config.json @@ -1,6 +1,11 @@ { "projectName": "Mermaid", "languages": [ + { + "id": "eventModel", + "grammar": "src/language/eventModel/eventModel.langium", + "fileExtensions": [".mmd", ".mermaid"] + }, { "id": "info", "grammar": "src/language/info/info.langium", diff --git a/packages/parser/src/language/eventModel/eventModel.langium b/packages/parser/src/language/eventModel/eventModel.langium new file mode 100644 index 0000000000..0e24e6ea96 --- /dev/null +++ b/packages/parser/src/language/eventModel/eventModel.langium @@ -0,0 +1,45 @@ +grammar EventModel +import "../common/common"; + +entry EventModel: + NEWLINE* + "eventModel-beta" EOL + TitleAndAccessibilities? + blocks+=Block* +; + +Block:(Pattern|Trigger|Query|Command|System|EdgeSet)EOL; + +Pattern: + "pattern" name=Name "{" EOL + roles+=Role* + "}" EOL +; +Role: + "role" name=Name "{" EOL + triggers+=Trigger* + "}" EOL +; +Trigger:"trigger" name=Name EOL; + +Query:"query" name=Name EOL; +Command:"command" name=Name EOL; + +System: + "system" name=Name "{" EOL + facts+=Fact* + "}" EOL +; +Fact:NEWLINE* "fact" name=Name EOL NEWLINE*; + +EdgeSet: ( + (from=Targets "-->" to=Targets) + | (to=Targets "<--" from=Targets) + ) EOL; + +Targets:targets+=UNQUOTED("&" targets +=UNQUOTED)*; + +Name: name=UNQUOTED("["(displayName=STRING|UNQUOTED)"]")?; + +terminal STRING: /"[^"]*"|'[^']*'/; +terminal UNQUOTED: /[a-zA-Z0-9]+/; From 3f96c9e182fc383caba9a93cee2b570632d9c6e4 Mon Sep 17 00:00:00 2001 From: sam schick Date: Sun, 15 Sep 2024 14:02:58 +0000 Subject: [PATCH 2/3] finish parser boilerplate --- .../parser/src/language/eventModel/index.ts | 1 + .../parser/src/language/eventModel/module.ts | 51 +++++++++++++++++++ packages/parser/src/language/index.ts | 3 ++ packages/parser/src/parse.ts | 10 +++- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 packages/parser/src/language/eventModel/index.ts create mode 100644 packages/parser/src/language/eventModel/module.ts diff --git a/packages/parser/src/language/eventModel/index.ts b/packages/parser/src/language/eventModel/index.ts new file mode 100644 index 0000000000..fd3c604b08 --- /dev/null +++ b/packages/parser/src/language/eventModel/index.ts @@ -0,0 +1 @@ +export * from './module.js'; diff --git a/packages/parser/src/language/eventModel/module.ts b/packages/parser/src/language/eventModel/module.ts new file mode 100644 index 0000000000..f99e88d234 --- /dev/null +++ b/packages/parser/src/language/eventModel/module.ts @@ -0,0 +1,51 @@ +import type { + DefaultSharedCoreModuleContext, + LangiumCoreServices, + LangiumSharedCoreServices, + Module, + PartialLangiumCoreServices, +} from 'langium'; +import { + inject, + createDefaultCoreModule, + createDefaultSharedCoreModule, + EmptyFileSystem, +} from 'langium'; +import { CommonValueConverter } from '../common/valueConverter.js'; +import { MermaidGeneratedSharedModule, EventModelGeneratedModule } from '../generated/module.js'; + +interface EventModelAddedServices { + parser: { + ValueConverter: CommonValueConverter; + }; +} + +export type EventModelServices = LangiumCoreServices & EventModelAddedServices; + +export const EventModelModule: Module< + EventModelServices, + PartialLangiumCoreServices & EventModelAddedServices +> = { + parser: { + ValueConverter: () => new CommonValueConverter(), + }, +}; + +export function createEventModelServices( + context: DefaultSharedCoreModuleContext = EmptyFileSystem +): { + shared: LangiumSharedCoreServices; + EventModel: EventModelServices; +} { + const shared: LangiumSharedCoreServices = inject( + createDefaultSharedCoreModule(context), + MermaidGeneratedSharedModule + ); + const EventModel: EventModelServices = inject( + createDefaultCoreModule({ shared }), + EventModelGeneratedModule, + EventModelModule + ); + shared.ServiceRegistry.register(EventModel); + return { shared, EventModel }; +} diff --git a/packages/parser/src/language/index.ts b/packages/parser/src/language/index.ts index c85a5a8b60..4594d40835 100644 --- a/packages/parser/src/language/index.ts +++ b/packages/parser/src/language/index.ts @@ -6,6 +6,7 @@ export { Pie, PieSection, Architecture, + EventModel, GitGraph, Branch, Commit, @@ -31,6 +32,7 @@ export { PieGeneratedModule, ArchitectureGeneratedModule, GitGraphGeneratedModule, + EventModelGeneratedModule, } from './generated/module.js'; export * from './gitGraph/index.js'; @@ -39,3 +41,4 @@ export * from './info/index.js'; export * from './packet/index.js'; export * from './pie/index.js'; export * from './architecture/index.js'; +export * from './eventModel/index.js'; diff --git a/packages/parser/src/parse.ts b/packages/parser/src/parse.ts index 86713c2f1b..933f79801f 100644 --- a/packages/parser/src/parse.ts +++ b/packages/parser/src/parse.ts @@ -1,8 +1,8 @@ import type { LangiumParser, ParseResult } from 'langium'; -import type { Info, Packet, Pie, Architecture, GitGraph } from './index.js'; +import type { Info, Packet, Pie, Architecture, GitGraph, EventModel } from './index.js'; -export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph; +export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | EventModel; const parsers: Record = {}; const initializers = { @@ -31,6 +31,11 @@ const initializers = { const parser = createGitGraphServices().GitGraph.parser.LangiumParser; parsers.gitGraph = parser; }, + eventModel: async () => { + const { createEventModelServices } = await import('./language/eventModel/index.js'); + const parser = createEventModelServices().EventModel.parser.LangiumParser; + parsers.eventModel = parser; + }, } as const; export async function parse(diagramType: 'info', text: string): Promise; @@ -38,6 +43,7 @@ export async function parse(diagramType: 'packet', text: string): Promise; export async function parse(diagramType: 'architecture', text: string): Promise; export async function parse(diagramType: 'gitGraph', text: string): Promise; +export async function parse(diagramType: 'eventModel', text: string): Promise; export async function parse( diagramType: keyof typeof initializers, From 3b234ac31fbdcabd4e6601dbe95b8016944153a3 Mon Sep 17 00:00:00 2001 From: sam schick Date: Mon, 23 Sep 2024 19:01:38 +0000 Subject: [PATCH 3/3] wip switching computers --- packages/mermaid/src/config.type.ts | 20 +- packages/mermaid/src/defaultConfig.ts | 3 + .../mermaid/src/diagrams/eventmodel/db.ts | 74 ++++++++ .../src/diagrams/eventmodel/detector.ts | 22 +++ .../src/diagrams/eventmodel/diagram.ts | 12 ++ .../src/diagrams/eventmodel/packet.spec.ts | 175 ++++++++++++++++++ .../mermaid/src/diagrams/eventmodel/parser.ts | 20 ++ .../src/diagrams/eventmodel/renderer.ts | 94 ++++++++++ .../mermaid/src/diagrams/eventmodel/styles.ts | 47 +++++ .../mermaid/src/diagrams/eventmodel/types.ts | 37 ++++ .../mermaid/src/schemas/config.schema.yaml | 10 + packages/parser/src/language/index.ts | 4 + 12 files changed, 513 insertions(+), 5 deletions(-) create mode 100644 packages/mermaid/src/diagrams/eventmodel/db.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/detector.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/diagram.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/packet.spec.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/parser.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/renderer.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/styles.ts create mode 100644 packages/mermaid/src/diagrams/eventmodel/types.ts diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index 035a158e0d..f58d4751f3 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -104,11 +104,11 @@ export interface MermaidConfig { * */ cycleBreakingStrategy?: - | 'GREEDY' - | 'DEPTH_FIRST' - | 'INTERACTIVE' - | 'MODEL_ORDER' - | 'GREEDY_MODEL_ORDER'; + | 'GREEDY' + | 'DEPTH_FIRST' + | 'INTERACTIVE' + | 'MODEL_ORDER' + | 'GREEDY_MODEL_ORDER'; }; darkMode?: boolean; htmlLabels?: boolean; @@ -197,6 +197,7 @@ export interface MermaidConfig { c4?: C4DiagramConfig; sankey?: SankeyDiagramConfig; packet?: PacketDiagramConfig; + eventModel?: EventModelDiagramConfig; block?: BlockDiagramConfig; dompurifyConfig?: DOMPurifyConfiguration; wrap?: boolean; @@ -1511,6 +1512,15 @@ export interface PacketDiagramConfig extends BaseDiagramConfig { export interface BlockDiagramConfig extends BaseDiagramConfig { padding?: number; } +/** + * The object containing configurations specific for gantt diagrams + * + * + * This interface was referenced by `MermaidConfig`'s JSON-Schema + * via the `definition` "EventModelDiagramConfig". + */ +export interface EventModelDiagramConfig extends BaseDiagramConfig { +} /** * This interface was referenced by `MermaidConfig`'s JSON-Schema * via the `definition` "FontConfig". diff --git a/packages/mermaid/src/defaultConfig.ts b/packages/mermaid/src/defaultConfig.ts index 97f3e0bb1a..54e6f21323 100644 --- a/packages/mermaid/src/defaultConfig.ts +++ b/packages/mermaid/src/defaultConfig.ts @@ -251,6 +251,9 @@ const config: RequiredDeep = { packet: { ...defaultConfigJson.packet, }, + eventModel: { + ...defaultConfigJson.eventModel, + } }; const keyify = (obj: any, prefix = ''): string[] => diff --git a/packages/mermaid/src/diagrams/eventmodel/db.ts b/packages/mermaid/src/diagrams/eventmodel/db.ts new file mode 100644 index 0000000000..0e67cddf89 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/db.ts @@ -0,0 +1,74 @@ +import { block } from 'marked'; +import { getConfig as commonGetConfig } from '../../config.js'; +import DEFAULT_CONFIG from '../../defaultConfig.js'; +import { ImperativeState } from '../../utils/imperativeState.js'; +import { + clear as commonClear, + getAccDescription, + getAccTitle, + getDiagramTitle, + setAccDescription, + setAccTitle, + setDiagramTitle, +} from '../common/commonDb.js'; +import { eventModel } from './detector.js'; +import type { EventModelData, EventModelDB } from './types.js'; +import type { EdgeSet, System, Pattern } from '@mermaid-js/parser'; + + +type Edge = EventModelData['edges'][number]; +type Node = EventModelData['nodes'][string]; + +const data = new ImperativeState((): EventModelData => ({ + nodes: {}, + edges: [], +})); + +const getEdges = (block: EdgeSet): Edge[] => { + const sources = block.from.flatMap(({ targets }) => targets); + const destinations = block.to.flatMap(({ targets }) => targets); + return sources.flatMap(from => destinations.map(to => ({ from, to }))); +} + +const getSystemNodes = (block: System): Record => { + +} + + +export const db: EventModelDB = { + clear() { + data.reset(); + commonClear(); + }, + getConfig() { + return { ...DEFAULT_CONFIG.eventModel, ...commonGetConfig() } + }, + addBlock(block) { + switch (block.$type) { + case 'Query': + case 'Command': + case 'Trigger': + data.records.nodes[block.name.name] = { + type: block.$type === 'Trigger' ? 'AutomatedTrigger' : block.$type, + name: block.name.name, + displayName: block.name.displayName, + } + return true; + case 'Pattern': + data.records.nodes = { ...data.records.nodes, ...getPatternNodes(block) }; + return true; + case 'System': + data.records.nodes = { ...data.records.nodes, ...getSystemNodes(block) }; + return true; + case 'EdgeSet': + data.records.edges = [...data.records.edges, ...getEdges(block)]; + return true; + } + }, + setAccTitle, + getAccTitle, + setDiagramTitle, + getDiagramTitle, + getAccDescription, + setAccDescription, +}; diff --git a/packages/mermaid/src/diagrams/eventmodel/detector.ts b/packages/mermaid/src/diagrams/eventmodel/detector.ts new file mode 100644 index 0000000000..6e0c799e4c --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/detector.ts @@ -0,0 +1,22 @@ +import type { + DiagramDetector, + DiagramLoader, + ExternalDiagramDefinition, +} from '../../diagram-api/types.js'; + +const id = 'eventModel'; + +const detector: DiagramDetector = (txt) => { + return /^\s*eventModel-beta/.test(txt); +}; + +const loader: DiagramLoader = async () => { + const { diagram } = await import('./diagram.js'); + return { id, diagram }; +}; + +export const eventModel: ExternalDiagramDefinition = { + id, + detector, + loader, +}; diff --git a/packages/mermaid/src/diagrams/eventmodel/diagram.ts b/packages/mermaid/src/diagrams/eventmodel/diagram.ts new file mode 100644 index 0000000000..a73a77c052 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/diagram.ts @@ -0,0 +1,12 @@ +import type { DiagramDefinition } from '../../diagram-api/types.js'; +import { db } from './db.js'; +import { parser } from './parser.js'; +import { renderer } from './renderer.js'; +import { styles } from './styles.js'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, +}; diff --git a/packages/mermaid/src/diagrams/eventmodel/packet.spec.ts b/packages/mermaid/src/diagrams/eventmodel/packet.spec.ts new file mode 100644 index 0000000000..2d7b278cd9 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/packet.spec.ts @@ -0,0 +1,175 @@ +import { it, describe, expect } from 'vitest'; +import { db } from './db.js'; +import { parser } from './parser.js'; + +const { clear, getPacket, getDiagramTitle, getAccTitle, getAccDescription } = db; + +describe('packet diagrams', () => { + beforeEach(() => { + clear(); + }); + + it('should handle a packet-beta definition', async () => { + const str = `packet-beta`; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getPacket()).toMatchInlineSnapshot('[]'); + }); + + it('should handle diagram with data and title', async () => { + const str = `packet-beta + title Packet diagram + accTitle: Packet accTitle + accDescr: Packet accDescription + 0-10: "test" + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getDiagramTitle()).toMatchInlineSnapshot('"Packet diagram"'); + expect(getAccTitle()).toMatchInlineSnapshot('"Packet accTitle"'); + expect(getAccDescription()).toMatchInlineSnapshot('"Packet accDescription"'); + expect(getPacket()).toMatchInlineSnapshot(` + [ + [ + { + "end": 10, + "label": "test", + "start": 0, + }, + ], + ] + `); + }); + + it('should handle single bits', async () => { + const str = `packet-beta + 0-10: "test" + 11: "single" + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getPacket()).toMatchInlineSnapshot(` + [ + [ + { + "end": 10, + "label": "test", + "start": 0, + }, + { + "end": 11, + "label": "single", + "start": 11, + }, + ], + ] + `); + }); + + it('should split into multiple rows', async () => { + const str = `packet-beta + 0-10: "test" + 11-90: "multiple" + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getPacket()).toMatchInlineSnapshot(` + [ + [ + { + "end": 10, + "label": "test", + "start": 0, + }, + { + "end": 31, + "label": "multiple", + "start": 11, + }, + ], + [ + { + "end": 63, + "label": "multiple", + "start": 32, + }, + ], + [ + { + "end": 90, + "label": "multiple", + "start": 64, + }, + ], + ] + `); + }); + + it('should split into multiple rows when cut at exact length', async () => { + const str = `packet-beta + 0-16: "test" + 17-63: "multiple" + `; + await expect(parser.parse(str)).resolves.not.toThrow(); + expect(getPacket()).toMatchInlineSnapshot(` + [ + [ + { + "end": 16, + "label": "test", + "start": 0, + }, + { + "end": 31, + "label": "multiple", + "start": 17, + }, + ], + [ + { + "end": 63, + "label": "multiple", + "start": 32, + }, + ], + ] + `); + }); + + it('should throw error if numbers are not continuous', async () => { + const str = `packet-beta + 0-16: "test" + 18-20: "error" + `; + await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Packet block 18 - 20 is not contiguous. It should start from 17.]` + ); + }); + + it('should throw error if numbers are not continuous for single packets', async () => { + const str = `packet-beta + 0-16: "test" + 18: "error" + `; + await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Packet block 18 - 18 is not contiguous. It should start from 17.]` + ); + }); + + it('should throw error if numbers are not continuous for single packets - 2', async () => { + const str = `packet-beta + 0-16: "test" + 17: "good" + 19: "error" + `; + await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Packet block 19 - 19 is not contiguous. It should start from 18.]` + ); + }); + + it('should throw error if end is less than start', async () => { + const str = `packet-beta + 0-16: "test" + 25-20: "error" + `; + await expect(parser.parse(str)).rejects.toThrowErrorMatchingInlineSnapshot( + `[Error: Packet block 25 - 20 is invalid. End must be greater than start.]` + ); + }); +}); diff --git a/packages/mermaid/src/diagrams/eventmodel/parser.ts b/packages/mermaid/src/diagrams/eventmodel/parser.ts new file mode 100644 index 0000000000..2a56280a5a --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/parser.ts @@ -0,0 +1,20 @@ +import type { EventModel } from '@mermaid-js/parser'; +import { parse } from '@mermaid-js/parser'; +import type { ParserDefinition } from '../../diagram-api/types.js'; +import { log } from '../../logger.js'; +import { populateCommonDb } from '../common/populateCommonDb.js'; +import { db } from './db.js'; + + +const populate = (ast: EventModel) => { + populateCommonDb(ast, db); + // TODO finish populate appropriately +}; + +export const parser: ParserDefinition = { + parse: async (input: string): Promise => { + const ast: EventModel = await parse('eventModel', input); + log.debug(ast); + populate(ast); + }, +}; diff --git a/packages/mermaid/src/diagrams/eventmodel/renderer.ts b/packages/mermaid/src/diagrams/eventmodel/renderer.ts new file mode 100644 index 0000000000..25445a2284 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/renderer.ts @@ -0,0 +1,94 @@ +import type { Diagram } from '../../Diagram.js'; +import type { PacketDiagramConfig } from '../../config.type.js'; +import type { DiagramRenderer, DrawDefinition, SVG, SVGGroup } from '../../diagram-api/types.js'; +import { selectSvgElement } from '../../rendering-util/selectSvgElement.js'; +import { configureSvgSize } from '../../setupGraphViewbox.js'; +import type { PacketDB, PacketWord } from './types.js'; + +const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => { + const db = diagram.db as PacketDB; + const config = db.getConfig(); + const { rowHeight, paddingY, bitWidth, bitsPerRow } = config; + const words = db.getPacket(); + const title = db.getDiagramTitle(); + const totalRowHeight = rowHeight + paddingY; + const svgHeight = totalRowHeight * (words.length + 1) - (title ? 0 : rowHeight); + const svgWidth = bitWidth * bitsPerRow + 2; + const svg: SVG = selectSvgElement(id); + + svg.attr('viewbox', `0 0 ${svgWidth} ${svgHeight}`); + configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth); + + for (const [word, packet] of words.entries()) { + drawWord(svg, packet, word, config); + } + + svg + .append('text') + .text(title) + .attr('x', svgWidth / 2) + .attr('y', svgHeight - totalRowHeight / 2) + .attr('dominant-baseline', 'middle') + .attr('text-anchor', 'middle') + .attr('class', 'packetTitle'); +}; + +const drawWord = ( + svg: SVG, + word: PacketWord, + rowNumber: number, + { rowHeight, paddingX, paddingY, bitWidth, bitsPerRow, showBits }: Required +) => { + const group: SVGGroup = svg.append('g'); + const wordY = rowNumber * (rowHeight + paddingY) + paddingY; + for (const block of word) { + const blockX = (block.start % bitsPerRow) * bitWidth + 1; + const width = (block.end - block.start + 1) * bitWidth - paddingX; + // Block rectangle + group + .append('rect') + .attr('x', blockX) + .attr('y', wordY) + .attr('width', width) + .attr('height', rowHeight) + .attr('class', 'packetBlock'); + + // Block label + group + .append('text') + .attr('x', blockX + width / 2) + .attr('y', wordY + rowHeight / 2) + .attr('class', 'packetLabel') + .attr('dominant-baseline', 'middle') + .attr('text-anchor', 'middle') + .text(block.label); + + if (!showBits) { + continue; + } + // Start byte count + const isSingleBlock = block.end === block.start; + const bitNumberY = wordY - 2; + group + .append('text') + .attr('x', blockX + (isSingleBlock ? width / 2 : 0)) + .attr('y', bitNumberY) + .attr('class', 'packetByte start') + .attr('dominant-baseline', 'auto') + .attr('text-anchor', isSingleBlock ? 'middle' : 'start') + .text(block.start); + + // Draw end byte count if it is not the same as start byte count + if (!isSingleBlock) { + group + .append('text') + .attr('x', blockX + width) + .attr('y', bitNumberY) + .attr('class', 'packetByte end') + .attr('dominant-baseline', 'auto') + .attr('text-anchor', 'end') + .text(block.end); + } + } +}; +export const renderer: DiagramRenderer = { draw }; diff --git a/packages/mermaid/src/diagrams/eventmodel/styles.ts b/packages/mermaid/src/diagrams/eventmodel/styles.ts new file mode 100644 index 0000000000..ff940d0e63 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/styles.ts @@ -0,0 +1,47 @@ +import type { DiagramStylesProvider } from '../../diagram-api/types.js'; +import { cleanAndMerge } from '../../utils.js'; +import type { PacketStyleOptions } from './types.js'; + +const defaultPacketStyleOptions: PacketStyleOptions = { + byteFontSize: '10px', + startByteColor: 'black', + endByteColor: 'black', + labelColor: 'black', + labelFontSize: '12px', + titleColor: 'black', + titleFontSize: '14px', + blockStrokeColor: 'black', + blockStrokeWidth: '1', + blockFillColor: '#efefef', +}; + +export const styles: DiagramStylesProvider = ({ packet }: { packet?: PacketStyleOptions } = {}) => { + const options = cleanAndMerge(defaultPacketStyleOptions, packet); + + return ` + .packetByte { + font-size: ${options.byteFontSize}; + } + .packetByte.start { + fill: ${options.startByteColor}; + } + .packetByte.end { + fill: ${options.endByteColor}; + } + .packetLabel { + fill: ${options.labelColor}; + font-size: ${options.labelFontSize}; + } + .packetTitle { + fill: ${options.titleColor}; + font-size: ${options.titleFontSize}; + } + .packetBlock { + stroke: ${options.blockStrokeColor}; + stroke-width: ${options.blockStrokeWidth}; + fill: ${options.blockFillColor}; + } + `; +}; + +export default styles; diff --git a/packages/mermaid/src/diagrams/eventmodel/types.ts b/packages/mermaid/src/diagrams/eventmodel/types.ts new file mode 100644 index 0000000000..e22ada3b72 --- /dev/null +++ b/packages/mermaid/src/diagrams/eventmodel/types.ts @@ -0,0 +1,37 @@ +import type { EventModel } from '@mermaid-js/parser'; +import type { EventModelDiagramConfig } from '../../config.type.js'; +import type { DiagramDBBase } from '../../diagram-api/types.js'; + +export interface EventModelDB extends DiagramDBBase { + addBlock: (word: EventModel['blocks'][number]) => boolean; +} + +export interface EventModelStyleOptions { + byteFontSize?: string; + startByteColor?: string; + endByteColor?: string; + labelColor?: string; + labelFontSize?: string; + blockStrokeColor?: string; + blockStrokeWidth?: string; + blockFillColor?: string; + titleColor?: string; + titleFontSize?: string; +} + +interface EventModelNodeBase { name: string, displayName?: string } +type EventModelNodeData = { + type: 'Fact', + system: string, +} | { + type: 'Query' | 'Command' | 'AutomatedTrigger' +} | { + type: 'Trigger', + pattern: string, + role: string +} + +export interface EventModelData { + nodes: Record; + edges: { from: string; to: string }[]; +} diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml index a7b3549ebf..11c3256851 100644 --- a/packages/mermaid/src/schemas/config.schema.yaml +++ b/packages/mermaid/src/schemas/config.schema.yaml @@ -52,6 +52,7 @@ required: - c4 - sankey - packet + - eventModel - block - look properties: @@ -287,6 +288,8 @@ properties: $ref: '#/$defs/SankeyDiagramConfig' packet: $ref: '#/$defs/PacketDiagramConfig' + eventModel: + $ref: '#/$defs/EventModelDiagramConfig' block: $ref: '#/$defs/BlockDiagramConfig' dompurifyConfig: @@ -2165,6 +2168,13 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file) minimum: 0 default: 5 + EventModelDiagramConfig: + title: Event Model Diagram Config + allOf: [{ $ref: '#/$defs/BaseDiagramConfig' }] + description: The object containing configurations specific for event model diagrams. + type: object + unevaluatedProperties: false + BlockDiagramConfig: title: Block Diagram Config allOf: [{ $ref: '#/$defs/BaseDiagramConfig' }] diff --git a/packages/parser/src/language/index.ts b/packages/parser/src/language/index.ts index 4594d40835..ce2925037f 100644 --- a/packages/parser/src/language/index.ts +++ b/packages/parser/src/language/index.ts @@ -23,6 +23,10 @@ export { isBranch, isCommit, isMerge, + EdgeSet, + System, + Pattern, + Role, } from './generated/ast.js'; export {