From 2812a0d12aee17eb88d826948569976df1233e3d Mon Sep 17 00:00:00 2001 From: quilicicf Date: Sat, 6 Sep 2025 14:15:48 +0200 Subject: [PATCH] feat(architecture): Add ids in generated SVG --- .changeset/deep-times-make.md | 5 ++ .../src/diagrams/architecture/svgDraw.spec.ts | 48 +++++++++++++++++++ .../src/diagrams/architecture/svgDraw.ts | 14 ++++-- 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 .changeset/deep-times-make.md create mode 100644 packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts diff --git a/.changeset/deep-times-make.md b/.changeset/deep-times-make.md new file mode 100644 index 000000000..3f126736f --- /dev/null +++ b/.changeset/deep-times-make.md @@ -0,0 +1,5 @@ +--- +'mermaid': minor +--- + +Add IDs in architecture diagrams diff --git a/packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts b/packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts new file mode 100644 index 000000000..21d56b5af --- /dev/null +++ b/packages/mermaid/src/diagrams/architecture/svgDraw.spec.ts @@ -0,0 +1,48 @@ +import { describe } from 'vitest'; +import { draw } from './architectureRenderer.js'; +import { Diagram } from '../../Diagram.js'; +import { addDetector } from '../../diagram-api/detectType.js'; +import architectureDetector from './architectureDetector.js'; +import { ensureNodeFromSelector, jsdomIt } from '../../tests/util.js'; + +const { id, detector, loader } = architectureDetector; + +addDetector(id, detector, loader); // Add architecture schemas to Mermaid + +describe('architecture diagram SVGs', () => { + jsdomIt('should add ids', async () => { + const svgNode = await drawDiagram(` + architecture-beta + group api(cloud)[API] + + service db(database)[Database] in api + service disk1(disk)[Storage] in api + service disk2(disk)[Storage] in api + service server(server)[Server] in api + + db:L -- R:server + disk1:T -- B:server + disk2:T -- B:db + `); + + const nodesForGroup = svgNode.querySelectorAll(`#group-api`); + expect(nodesForGroup.length).toBe(1); + + const serviceIds = [...svgNode.querySelectorAll(`[id^=service-]`)].map(({ id }) => id).sort(); + expect(serviceIds).toStrictEqual([ + 'service-db', + 'service-disk1', + 'service-disk2', + 'service-server', + ]); + + const edgeIds = [...svgNode.querySelectorAll(`.edge[id^=L_]`)].map(({ id }) => id).sort(); + expect(edgeIds).toStrictEqual(['L_db_server_0', 'L_disk1_server_0', 'L_disk2_db_0']); + }); +}); + +async function drawDiagram(diagramText: string): Promise { + const diagram = await Diagram.fromText(diagramText, {}); + await draw('NOT_USED', 'svg', '1.0.0', diagram); + return ensureNodeFromSelector('#svg'); +} diff --git a/packages/mermaid/src/diagrams/architecture/svgDraw.ts b/packages/mermaid/src/diagrams/architecture/svgDraw.ts index 6e470caa2..b35e453e7 100644 --- a/packages/mermaid/src/diagrams/architecture/svgDraw.ts +++ b/packages/mermaid/src/diagrams/architecture/svgDraw.ts @@ -20,6 +20,7 @@ import { type ArchitectureJunction, type ArchitectureService, } from './architectureTypes.js'; +import { getEdgeId } from '../../utils.js'; export const drawEdges = async function ( edgesEl: D3Element, @@ -91,7 +92,8 @@ export const drawEdges = async function ( g.insert('path') .attr('d', `M ${startX},${startY} L ${midX},${midY} L${endX},${endY} `) - .attr('class', 'edge'); + .attr('class', 'edge') + .attr('id', getEdgeId(source, target, { prefix: 'L' })); if (sourceArrow) { const xShift = isArchitectureDirectionX(sourceDir) @@ -206,8 +208,9 @@ export const drawGroups = async function ( if (data.type === 'group') { const { h, w, x1, y1 } = node.boundingBox(); - groupsEl - .append('rect') + const groupsNode = groupsEl.append('rect'); + groupsNode + .attr('id', `group-${data.id}`) .attr('x', x1 + halfIconSize) .attr('y', y1 + halfIconSize) .attr('width', w) @@ -262,6 +265,7 @@ export const drawGroups = async function ( ')' ); } + db.setElementForId(data.id, groupsNode); } }) ); @@ -342,9 +346,9 @@ export const drawServices = async function ( ); } - serviceElem.attr('class', 'architecture-service'); + serviceElem.attr('id', `service-${service.id}`).attr('class', 'architecture-service'); - const { width, height } = serviceElem._groups[0][0].getBBox(); + const { width, height } = serviceElem.node().getBBox(); service.width = width; service.height = height; db.setElementForId(service.id, serviceElem);