From 0a23304d1a7ca726a5024e8a7daada86678cbbb0 Mon Sep 17 00:00:00 2001 From: darshanr0107 Date: Mon, 29 Sep 2025 15:13:19 +0530 Subject: [PATCH] fix: ensure architecture diagram uses unified rendering on-behalf-of: @Mermaid-Chart --- .../diagrams/architecture/architectureDb.ts | 158 ++++++++++++++++-- .../architecture/architectureDiagram.ts | 2 +- .../architectureRenderer-unified.ts | 50 ++++++ .../architecture/architectureTypes.ts | 4 +- 4 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 packages/mermaid/src/diagrams/architecture/architectureRenderer-unified.ts diff --git a/packages/mermaid/src/diagrams/architecture/architectureDb.ts b/packages/mermaid/src/diagrams/architecture/architectureDb.ts index 4764671e8..2262915f1 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureDb.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureDb.ts @@ -3,7 +3,9 @@ import type { ArchitectureDiagramConfig } from '../../config.type.js'; import DEFAULT_CONFIG from '../../defaultConfig.js'; import type { DiagramDB } from '../../diagram-api/types.js'; import type { D3Element } from '../../types.js'; -import { cleanAndMerge } from '../../utils.js'; +import { cleanAndMerge, getEdgeId } from '../../utils.js'; +import type { LayoutData, Node, Edge } from '../../rendering-util/types.js'; + import { clear as commonClear, getAccDescription, @@ -351,15 +353,147 @@ export class ArchitectureDB implements DiagramDB { public getDiagramTitle = getDiagramTitle; public getAccDescription = getAccDescription; public setAccDescription = setAccDescription; -} -/** - * Typed wrapper for resolving an architecture diagram's config fields. Returns the default value if undefined - * @param field - the config field to access - * @returns - */ -// export function getConfigField( -// field: T -// ): Required[T] { -// return db.getConfig()[field]; -// } + /** + * Converts architecture diagram data to LayoutData format for unified rendering + */ + public getData(): LayoutData { + const config = commonGetConfig(); + const nodes: Node[] = []; + const edges: Edge[] = []; + + const groups = this.getGroups(); + for (const group of groups) { + const padding = this.getConfigField('padding'); + const fontSize = this.getConfigField('fontSize'); + + const groupWidth = 200; + let groupHeight = 150; + + if (group.title || group.icon) { + groupHeight += fontSize + padding; + } + + nodes.push({ + id: group.id, + label: group.title, + parentId: group.in, + isGroup: true, + shape: 'rect', + icon: group.icon, + width: groupWidth, + height: groupHeight, + padding: padding, + cssClasses: 'architecture-group', + cssCompiledStyles: [ + 'stroke: #cccccc', + 'stroke-width: 2px', + 'stroke-dasharray: 8,8', + 'fill: transparent', + ], + labelStyle: '', + look: config.look || 'classic', + rx: 5, + ry: 5, + }); + } + + const services = this.getServices(); + for (const service of services) { + const iconSize = this.getConfigField('iconSize'); + let nodeWidth = iconSize; + let nodeHeight = iconSize; + + if (service.title) { + nodeHeight += iconSize * 0.3; + nodeWidth = Math.max(nodeWidth, iconSize * 1.5); + } + + nodes.push({ + id: service.id, + label: service.title, + parentId: service.in, + isGroup: false, + shape: service.icon || (service as any).iconText ? 'icon' : 'squareRect', + icon: service.icon ? `mermaid-architecture:${service.icon}` : 'mermaid-architecture:blank', + width: service.width || nodeWidth, + height: service.height || nodeHeight, + cssClasses: 'architecture-service', + look: config.look, + padding: this.getConfigField('padding') / 4, + description: (service as any).iconText ? [(service as any).iconText] : undefined, + assetWidth: iconSize, + assetHeight: iconSize, + }); + } + + const junctions = this.getJunctions(); + for (const junction of junctions) { + nodes.push({ + id: junction.id, + parentId: junction.in, + isGroup: false, + shape: 'squareRect', + width: 2, + height: 2, + cssClasses: 'architecture-junction', + look: config.look, + type: 'junction' as any, + padding: 0, + }); + } + + const architectureEdges = this.getEdges(); + let edgeCounter = 0; + for (const edge of architectureEdges) { + const edgeData = { + id: getEdgeId(edge.lhsId, edge.rhsId, { counter: edgeCounter, prefix: 'L' }), + start: edge.lhsId, + end: edge.rhsId, + source: edge.lhsId, + target: edge.rhsId, + label: edge.title || '', + labelpos: 'c', + type: 'normal', + minlen: 2, + weight: 1, + classes: 'edge-thickness-normal edge-pattern-solid architecture-edge', + look: config.look || 'classic', + curve: 'linear', + arrowTypeStart: edge.lhsInto ? 'point' : 'none', + arrowTypeEnd: edge.rhsInto ? 'point' : 'none', + arrowheadStyle: 'fill: #333', + thickness: 'normal', + pattern: 'solid', + style: ['stroke: #333333', 'stroke-width: 3px', 'fill: none'], + cssCompiledStyles: [], + labelStyle: [], + lhsDir: edge.lhsDir, + rhsDir: edge.rhsDir, + lhsInto: edge.lhsInto, + rhsInto: edge.rhsInto, + lhsGroup: edge.lhsGroup, + rhsGroup: edge.rhsGroup, + } as Edge & { + lhsDir: any; + rhsDir: any; + lhsInto?: boolean; + rhsInto?: boolean; + lhsGroup?: boolean; + rhsGroup?: boolean; + }; + + edges.push(edgeData); + edgeCounter++; + } + + const result = { + nodes, + edges, + config, + dataStructures: this.getDataStructures(), + }; + + return result; + } +} diff --git a/packages/mermaid/src/diagrams/architecture/architectureDiagram.ts b/packages/mermaid/src/diagrams/architecture/architectureDiagram.ts index 1d390a3ab..79cf991b4 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureDiagram.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureDiagram.ts @@ -2,7 +2,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js'; import { parser } from './architectureParser.js'; import { ArchitectureDB } from './architectureDb.js'; import styles from './architectureStyles.js'; -import { renderer } from './architectureRenderer.js'; +import { renderer } from './architectureRenderer-unified.js'; export const diagram: DiagramDefinition = { parser, diff --git a/packages/mermaid/src/diagrams/architecture/architectureRenderer-unified.ts b/packages/mermaid/src/diagrams/architecture/architectureRenderer-unified.ts new file mode 100644 index 000000000..1edb1feba --- /dev/null +++ b/packages/mermaid/src/diagrams/architecture/architectureRenderer-unified.ts @@ -0,0 +1,50 @@ +import { getConfig } from '../../diagram-api/diagramAPI.js'; +import type { DiagramStyleClassDef } from '../../diagram-api/types.js'; +import { log } from '../../logger.js'; +import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js'; +import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js'; +import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js'; +import type { LayoutData } from '../../rendering-util/types.js'; +import utils from '../../utils.js'; + +import { registerIconPacks } from '../../rendering-util/icons.js'; +import { architectureIcons } from './architectureIcons.js'; + +export const getClasses = function ( + _text: string, + _diagramObj: any +): Map { + return new Map(); +}; + +export const draw = async function (_text: string, id: string, _version: string, diag: any) { + registerIconPacks([ + { + name: architectureIcons.prefix, + icons: architectureIcons, + }, + ]); + const { securityLevel, architecture: conf, layout } = getConfig(); + + const data4Layout = diag.db.getData() as LayoutData; + + const svg = getDiagramElement(id, securityLevel); + + data4Layout.type = diag.type; + data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout, { fallback: 'dagre' }); + + data4Layout.nodeSpacing = 100; + data4Layout.rankSpacing = 100; + data4Layout.markers = ['point']; + data4Layout.diagramId = id; + + log.debug('Architecture layout data:', data4Layout); + await render(data4Layout, svg); + + const padding = conf?.padding ?? 8; + utils.insertTitle(svg, 'architectureTitleText', 0, diag.db.getDiagramTitle()); + + setupViewPortForSVG(svg, padding, 'architecture', conf?.useMaxWidth ?? true); +}; + +export const renderer = { draw }; diff --git a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts index c61df11ff..93aef92a8 100644 --- a/packages/mermaid/src/diagrams/architecture/architectureTypes.ts +++ b/packages/mermaid/src/diagrams/architecture/architectureTypes.ts @@ -2,6 +2,7 @@ import type { DiagramDBBase } from '../../diagram-api/types.js'; import type { ArchitectureDiagramConfig } from '../../config.type.js'; import type { D3Element } from '../../types.js'; import type cytoscape from 'cytoscape'; +import type { LayoutData } from '../../rendering-util/types.js'; /*=======================================*\ | Architecture Diagram Types | @@ -256,7 +257,8 @@ export interface ArchitectureDB extends DiagramDBBase getEdges: () => ArchitectureEdge[]; setElementForId: (id: string, element: D3Element) => void; getElementById: (id: string) => D3Element; - getDataStructures: () => ArchitectureDataStructures; + getData: () => LayoutData; + getDirection: () => string; } export type ArchitectureAdjacencyList = Record;