diff --git a/.eslintignore b/.eslintignore
index 04348c410..1db5125d0 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -4,4 +4,5 @@ docs/Setup.md
cypress.config.js
cypress/plugins/index.js
coverage
-*.json
\ No newline at end of file
+*.json
+node_modules
diff --git a/.github/ISSUE_TEMPLATE/diagram_proposal.yml b/.github/ISSUE_TEMPLATE/diagram_proposal.yml
index 67dad5d3a..59bda6d6d 100644
--- a/.github/ISSUE_TEMPLATE/diagram_proposal.yml
+++ b/.github/ISSUE_TEMPLATE/diagram_proposal.yml
@@ -3,6 +3,7 @@ description: Suggest a new Diagram Type to add to Mermaid.
labels:
- 'Status: Triage'
- 'Type: Enhancement'
+ - 'Type: New Diagram'
body:
- type: markdown
@@ -17,6 +18,14 @@ body:
- Use a clear and concise title
- Fill out the text fields with as much detail as possible.
- Never be shy to give us screenshots and/or code samples. It will help!
+
+ ## Example issues
+
+ Refer to the discussions here to get an idea of how the diagram syntax is created.
+
+ - https://github.com/mermaid-js/mermaid/issues/4269
+ - https://github.com/mermaid-js/mermaid/issues/4282
+
- type: textarea
attributes:
label: Proposal
@@ -35,8 +44,17 @@ body:
description: If applicable, add screenshots to show possible examples of how the diagram may look like.
- type: textarea
attributes:
- label: Code Sample
+ label: Syntax
description: |-
- If applicable, add a code sample for how to implement this new diagram.
- The text will automatically be rendered as JavaScript code.
- render: javascript
+ If possible, include a syntax which could be used to write the diagram.
+ Try to add one or two examples of valid use-cases here.
+ - type: dropdown
+ id: implementation
+ attributes:
+ label: Implementation
+ description: |-
+ Would you like to implement this yourself, or is it a proposal for the community?
+ If there is no corresponding PR from your side after 30 days, the diagram will be open for everyone to implement.
+ options:
+ - I will try and implement it myself.
+ - This is a proposal which I'd love to see built into mermaid by the wonderful community.
diff --git a/.vite/build.ts b/.vite/build.ts
index c2f8f08f5..a8cfe919c 100644
--- a/.vite/build.ts
+++ b/.vite/build.ts
@@ -44,6 +44,11 @@ const packageOptions = {
packageName: 'mermaid-example-diagram',
file: 'detector.ts',
},
+ 'mermaid-zenuml': {
+ name: 'mermaid-zenuml',
+ packageName: 'mermaid-zenuml',
+ file: 'detector.ts',
+ },
};
interface BuildOptions {
@@ -146,6 +151,7 @@ if (watch) {
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
if (!mermaidOnly) {
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
+ build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
}
} else if (visualize) {
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
diff --git a/.vite/server.ts b/.vite/server.ts
index 5a86b3d5b..41e510c83 100644
--- a/.vite/server.ts
+++ b/.vite/server.ts
@@ -15,6 +15,7 @@ async function createServer() {
app.use(cors());
app.use(express.static('./packages/mermaid/dist'));
+ app.use(express.static('./packages/mermaid-zenuml/dist'));
app.use(express.static('./packages/mermaid-example-diagram/dist'));
app.use(vite.middlewares);
app.use(express.static('demos'));
diff --git a/cSpell.json b/cSpell.json
index e72a7bb2b..0c565d48e 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -7,6 +7,7 @@
"alois",
"aloisklink",
"antiscript",
+ "antlr",
"appli",
"applitools",
"asciidoctor",
@@ -86,6 +87,7 @@
"mkdocs",
"mmorel",
"mult",
+ "nextra",
"orlandoni",
"pathe",
"pbrolin",
@@ -137,7 +139,8 @@
"vitepress",
"vueuse",
"xlink",
- "yash"
+ "yash",
+ "zenuml"
],
"patterns": [
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
diff --git a/cypress/helpers/util.js b/cypress/helpers/util.js
index 7ec960b97..4d13b3590 100644
--- a/cypress/helpers/util.js
+++ b/cypress/helpers/util.js
@@ -60,7 +60,7 @@ export const renderGraph = (graphStr, options, api) => {
openURLAndVerifyRendering(url, options);
};
-const openURLAndVerifyRendering = (url, options, validation = undefined) => {
+export const openURLAndVerifyRendering = (url, options, validation = undefined) => {
const useAppli = Cypress.env('useAppli');
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
diff --git a/cypress/integration/other/ghsa.spec.js b/cypress/integration/other/ghsa.spec.js
index 8f28d9f53..912f35728 100644
--- a/cypress/integration/other/ghsa.spec.js
+++ b/cypress/integration/other/ghsa.spec.js
@@ -1,4 +1,4 @@
-import { urlSnapshotTest } from '../../helpers/util.js';
+import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.js';
describe('CSS injections', () => {
it('should not allow CSS injections outside of the diagram', () => {
@@ -13,4 +13,11 @@ describe('CSS injections', () => {
flowchart: { htmlLabels: false },
});
});
+ it('should not allow manipulating styletags using arrowheads', () => {
+ openURLAndVerifyRendering('http://localhost:9000/xss23-css.html', {
+ logLevel: 1,
+ arrowMarkerAbsolute: false,
+ flowchart: { htmlLabels: true },
+ });
+ });
});
diff --git a/cypress/integration/rendering/flowchart-elk.spec.js b/cypress/integration/rendering/flowchart-elk.spec.js
index d0ef42c5d..4f90646a2 100644
--- a/cypress/integration/rendering/flowchart-elk.spec.js
+++ b/cypress/integration/rendering/flowchart-elk.spec.js
@@ -684,6 +684,20 @@ A --> B
{ titleTopMargin: 0 }
);
});
+ it('elk: should include classes on the edges', () => {
+ renderGraph(
+ `flowchart-elk TD
+ A --> B --> C --> D
+ `,
+ {}
+ );
+ cy.get('svg').should((svg) => {
+ const edges = svg.querySelectorAll('.edges > path');
+ edges.forEach((edge) => {
+ expect(edge).to.have.class('flowchart-link');
+ });
+ });
+ });
describe('Markdown strings flowchart-elk (#4220)', () => {
describe('html labels', () => {
it('With styling and classes', () => {
diff --git a/cypress/integration/rendering/mindmap.spec.ts b/cypress/integration/rendering/mindmap.spec.ts
index 94b3f9ca0..e390beaee 100644
--- a/cypress/integration/rendering/mindmap.spec.ts
+++ b/cypress/integration/rendering/mindmap.spec.ts
@@ -52,6 +52,17 @@ root[A root with a long text that wraps to keep the node size in check]
);
});
+ it('a root with wrapping text and long words that exceed width', () => {
+ imgSnapshotTest(
+ `mindmap
+root[A few smaller words but then averylongsetofcharacterswithoutwhitespacetoseparate that we expect to wrapontonextlinesandnotexceedwidthparameters]
+ `,
+ {},
+ undefined,
+ shouldHaveRoot
+ );
+ });
+
it('a root with an icon', () => {
imgSnapshotTest(
`mindmap
diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js
index e5459637b..185cc4133 100644
--- a/cypress/integration/rendering/sequencediagram.spec.js
+++ b/cypress/integration/rendering/sequencediagram.spec.js
@@ -88,6 +88,16 @@ context('Sequence diagram', () => {
{}
);
});
+ it('should handle empty lines', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ Alice->>John: Hello John
+ John-->>Alice: Great
day!
+ `,
+ {}
+ );
+ });
it('should handle line breaks and wrap annotations', () => {
imgSnapshotTest(
`
diff --git a/cypress/integration/rendering/zenuml.spec.js b/cypress/integration/rendering/zenuml.spec.js
new file mode 100644
index 000000000..f317fbe82
--- /dev/null
+++ b/cypress/integration/rendering/zenuml.spec.js
@@ -0,0 +1,19 @@
+import { imgSnapshotTest } from '../../helpers/util.js';
+
+describe('Zen UML', () => {
+ it('Basic Zen UML diagram', () => {
+ imgSnapshotTest(
+ `
+ zenuml
+ A.method() {
+ if(x) {
+ B.method() {
+ selfCall() { return X }
+ }
+ }
+ }
+ `,
+ {}
+ );
+ });
+});
diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js
index a99c150f1..0b566e329 100644
--- a/cypress/platform/viewer.js
+++ b/cypress/platform/viewer.js
@@ -1,5 +1,6 @@
import mermaid2 from './mermaid.esm.mjs';
import externalExample from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
+import zenUml from '../../packages/mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
function b64ToUtf8(str) {
return decodeURIComponent(escape(window.atob(str)));
@@ -44,7 +45,7 @@ const contentLoaded = async function () {
document.getElementsByTagName('body')[0].appendChild(div);
}
- await mermaid2.registerExternalDiagrams([externalExample]);
+ await mermaid2.registerExternalDiagrams([externalExample, zenUml]);
mermaid2.initialize(graphObj.mermaid);
await mermaid2.run();
}
diff --git a/cypress/platform/xss23-css.html b/cypress/platform/xss23-css.html
new file mode 100644
index 000000000..cc5b6f0bf
--- /dev/null
+++ b/cypress/platform/xss23-css.html
@@ -0,0 +1,85 @@
+
+