Skip to content

Commit

Permalink
Allow architecture diagrams to support any character for titles
Browse files Browse the repository at this point in the history
Architecture diagrams with Markdown
  • Loading branch information
wizbit committed Nov 18, 2024
1 parent 8328f74 commit 67d928f
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 72 deletions.
149 changes: 86 additions & 63 deletions cypress/integration/rendering/architecture.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { imgSnapshotTest, urlSnapshotTest } from '../../helpers/util.ts';

describe.skip('architecture diagram', () => {
describe('architecture diagram', () => {
it('should render a simple architecture diagram with groups', () => {
imgSnapshotTest(
`architecture-beta
Expand All @@ -10,12 +10,12 @@ describe.skip('architecture diagram', () => {
service disk1(disk)[Storage] in api
service disk2(disk)[Storage] in api
service server(server)[Server] in api
service gateway(internet)[Gateway]
service gateway(internet)[Gateway]
db L--R server
disk1 T--B server
disk2 T--B db
server T--B gateway
db:L -- R:server
disk1:T -- B:server
disk2:T -- B:db
server:T-- B:gateway
`
);
});
Expand All @@ -25,17 +25,17 @@ describe.skip('architecture diagram', () => {
group api[API]
group public[Public API] in api
group private[Private API] in api
service serv1(server)[Server] in public
service serv2(server)[Server] in private
service db(database)[Database] in private
service gateway(internet)[Gateway] in api
serv1 B--T serv2
serv2 L--R db
serv1 L--R gateway
serv1:B -- T:serv2
serv2:L -- R:db
serv1:L -- R:gateway
`
);
});
Expand All @@ -54,11 +54,11 @@ describe.skip('architecture diagram', () => {
service serv1(server)[Server 1]
service serv2(server)[Server 2]
service disk(disk)[Disk]
db L--R s3
serv1 L--T s3
serv2 L--B s3
serv1 T--B disk
db:L--R:s3
serv1:L--T:s3
serv2:L--B:s3
serv1:T--B:disk
`
);
});
Expand All @@ -70,16 +70,16 @@ describe.skip('architecture diagram', () => {
service servR(server)[Server 3]
service servT(server)[Server 4]
service servB(server)[Server 5]
servC (L--R) servL
servC (R--L) servR
servC (T--B) servT
servC (B--T) servB
servL (T--L) servT
servL (B--L) servB
servR (T--R) servT
servR (B--R) servB
servC:L<-->R:servL
servC:R<-->L:servR
servC:T<-->B:servT
servC:B<-->T:servB
servL:T<-->L:servT
servL:B<-->L:servB
servR:T<-->R:servT
servR:B<-->R:servB
`
);
});
Expand All @@ -91,17 +91,17 @@ describe.skip('architecture diagram', () => {
group top_group(cloud)[Top]
group bottom_group(cloud)[Bottom]
group center_group(cloud)[Center]
service left_disk(disk)[Disk] in left_group
service right_disk(disk)[Disk] in right_group
service top_disk(disk)[Disk] in top_group
service bottom_disk(disk)[Disk] in bottom_group
service center_disk(disk)[Disk] in center_group
left_disk{group} (R--L) center_disk{group}
right_disk{group} (L--R) center_disk{group}
top_disk{group} (B--T) center_disk{group}
bottom_disk{group} (T--B) center_disk{group}
left_disk{group}:R <--> L:center_disk{group}
right_disk{group}:L <--> R:center_disk{group}
top_disk{group}:B <--> T:center_disk{group}
bottom_disk{group}:T <--> B:center_disk{group}
`
);
});
Expand All @@ -113,16 +113,16 @@ describe.skip('architecture diagram', () => {
service servR(server)[Server 3]
service servT(server)[Server 4]
service servB(server)[Server 5]
servC L-[Label]-R servL
servC R-[Label]-L servR
servC T-[Label]-B servT
servC B-[Label]-T servB
servL T-[Label]-L servT
servL B-[Label]-L servB
servR T-[Label]-R servT
servR B-[Label]-R servB
servC:L-[Label]-R:servL
servC:R-[Label]-L:servR
servC:T-[Label]-B:servT
servC:B-[Label]-T:servB
servL:T-[Label]-L:servT
servL:B-[Label]-L:servB
servR:T-[Label]-R:servT
servR:B-[Label]-R:servB
`
);
});
Expand All @@ -136,13 +136,13 @@ describe.skip('architecture diagram', () => {
service bottom_gateway(internet)[Gateway]
junction juncC
junction juncR
left_disk R--L juncC
top_disk B--T juncC
bottom_disk T--B juncC
juncC R--L juncR
top_gateway B--T juncR
bottom_gateway T--B juncR
left_disk:R -- L:juncC
top_disk:B -- T:juncC
bottom_disk:T -- B:juncC
juncC:R -- L:juncR
top_gateway:B -- T:juncR
bottom_gateway:T -- B:juncR
`
);
});
Expand All @@ -158,23 +158,46 @@ describe.skip('architecture diagram', () => {
service bottom_gateway(internet)[Gateway] in right
junction juncC in left
junction juncR in right
left_disk R--L juncC
top_disk B--T juncC
bottom_disk T--B juncC
top_gateway (B--T juncR
bottom_gateway (T--B juncR
juncC{group} R--L) juncR{group}
left_disk:R -- L:juncC
top_disk:B -- T:juncC
bottom_disk:T -- B:juncC
top_gateway:B <-- T:juncR
bottom_gateway:T <-- B:juncR
juncC{group}:R --> L:juncR{group}
`
);
});

it('should render unicode', () => {
imgSnapshotTest(
`architecture-beta
service left_disk(disk)[Disk]
service right_disk(disk)["❤ Disk"]
left_disk:R -- L:right_disk
`
);
});

it('should render markdown', () => {
imgSnapshotTest(
`architecture-beta
service left_disk(disk)["\`This **is** _Markdown_\`"]
service right_disk(disk)["\`Line1
Line 2
Line 3\`"]
left_disk:R -- L:right_disk
`
);
});
});

// Skipped as the layout is not deterministic, and causes issues in E2E tests.
describe.skip('architecture - external', () => {
describe('architecture - external', () => {
it('should allow adding external icons', () => {
urlSnapshotTest('http://localhost:9000/architecture-external.html');
});
Expand Down
5 changes: 5 additions & 0 deletions cypress/platform/architecture-external.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ <h2>External Icons Demo</h2>
service ec2(logos:aws-ec2)[Server]
service api(logos:aws-api-gateway)[Api Gateway]
service fa(fa:image)[Font Awesome Icon]

api:L -- R:ec2
api:B -- T:s3
fa:L -- R:s3
fa:T -- B:ec2
</pre>

<script type="module">
Expand Down
41 changes: 40 additions & 1 deletion demos/architecture.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h2>Simple diagram with groups</h2>
service disk1(disk)[Storage] in api
service disk2(disk)[Storage] in api
service server(server)[Server] in api
service gateway(internet)[Gateway]
service gateway(internet)[Gateway]

db:L -- R:server
disk1:T -- B:server
Expand Down Expand Up @@ -226,13 +226,52 @@ <h2>Junction Demo Groups</h2>
</pre>
<hr />

<h2>Unicode</h2>
<pre class="mermaid">
architecture-beta
service left_disk(disk)["[email protected]"]
service right_disk(disk)["❤ Disk"]

left_disk:R -- L:right_disk
</pre>
<hr />

<h2>Markdown</h2>
<pre class="mermaid">
architecture-beta
service left_disk(disk)["`This **is** _Markdown_`"]
service right_disk(disk)["`Line1
Line 2
Line 3`"]

left_disk:R -- L:right_disk
</pre>
<hr />

<h2>Katex</h2>
<pre class="mermaid">
architecture-beta
service left_disk(disk)["`$$f(\relax{x}) = \int_{-\infty}^\infty \hat{f}(\xi)\,e^{2 \pi i \xi x}\,d\xi$$`"]
service center_disk(disk)["`$$\Bigg(\bigg(\Big(\big((\frac{-b\pm\sqrt{b^2-4ac}}{2a})\big)\Big)\bigg)\Bigg)$$`"]
service right_disk(disk)["`$$1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots}}}}$$`"]

left_disk:R -- L:center_disk
center_disk:R -- L:right_disk
</pre>
<hr />

<h2>External Icons Demo</h2>
<pre class="mermaid">
architecture-beta
service s3(logos:aws-s3)[Cloud Store]
service ec2(logos:aws-ec2)[Server]
service api(logos:aws-api-gateway)[Api Gateway]
service fa(fa:image)[Font Awesome Icon]

api:L -- R:ec2
api:B -- T:s3
fa:L -- R:s3
fa:T -- B:ec2
</pre>

<script type="module">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,7 @@ test('markdownToHTML - auto wrapping', () => {
)
).toMatchInlineSnapshot('"<p>Hello, how do<br/>you do?</p>"');
});

test('markdownToHTML - email address', () => {
expect(markdownToHTML(`[email protected]`)).toMatchInlineSnapshot('"<p>[email protected]</p>"');
});
2 changes: 2 additions & 0 deletions packages/mermaid/src/rendering-util/handle-markdown-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ export function markdownToHTML(markdown: string, { markdownAutoWrap }: MermaidCo
return `${node.text}`;
} else if (node.type === 'escape') {
return node.text;
} else if (node.type === 'link') {
return node.text;
}
return `Unsupported markdown: ${node.type}`;
}
Expand Down
12 changes: 5 additions & 7 deletions packages/parser/src/language/architecture/architecture.langium
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ import "../common/common";

entry Architecture:
NEWLINE*
"architecture-beta"
(
NEWLINE* TitleAndAccessibilities
| NEWLINE* Statement*
| NEWLINE*
)
"architecture-beta" EOL
TitleAndAccessibilities? Statement*
;

fragment Statement:
Expand Down Expand Up @@ -50,6 +46,8 @@ terminal ARROW_DIRECTION: 'L' | 'R' | 'T' | 'B';
terminal ARCH_ID: /[\w]+/;
terminal ARCH_TEXT_ICON: /\("[^"]+"\)/;
terminal ARCH_ICON: /\([\w-:]+\)/;
terminal ARCH_TITLE: /\[[\w ]+\]/;
terminal fragment ARCH_TITLE_MARKDOWN: '["`' -> '`"]';
terminal fragment ARCH_TITLE_SIMPLE: /\[([\w ]+|"([^"]|\\")+")\]/;
terminal ARCH_TITLE: ARCH_TITLE_MARKDOWN | ARCH_TITLE_SIMPLE;
terminal ARROW_GROUP: /\{group\}/;
terminal ARROW_INTO: /<|>/;
13 changes: 12 additions & 1 deletion packages/parser/src/language/architecture/valueConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@ export class ArchitectureValueConverter extends AbstractMermaidValueConverter {
} else if (rule.name === 'ARCH_TEXT_ICON') {
return input.replace(/["()]/g, '');
} else if (rule.name === 'ARCH_TITLE') {
return input.replace(/[[\]]/g, '').trim();
if (input.startsWith('["`') && input.endsWith('`"]')) {
// markdown
return input.substring(3, input.length - 3).trim();
} else if (input.startsWith('["')) {
// unicode or markdown
return input
.substring(2, input.length - 2)
.replace(/\\"/g, '"')
.trim();
}
// simple
return input.substring(1, input.length - 1).trim();
}
return undefined;
}
Expand Down
Loading

0 comments on commit 67d928f

Please sign in to comment.