mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-20 08:46:44 +02:00
Add zenuml
This commit is contained in:
@@ -43,6 +43,11 @@ const packageOptions = {
|
|||||||
packageName: 'mermaid-example-diagram',
|
packageName: 'mermaid-example-diagram',
|
||||||
file: 'detector.ts',
|
file: 'detector.ts',
|
||||||
},
|
},
|
||||||
|
'mermaid-zenuml': {
|
||||||
|
name: 'mermaid-zenuml',
|
||||||
|
packageName: 'mermaid-zenuml',
|
||||||
|
file: 'detector.ts',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
interface BuildOptions {
|
interface BuildOptions {
|
||||||
@@ -139,6 +144,7 @@ if (watch) {
|
|||||||
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||||
if (!mermaidOnly) {
|
if (!mermaidOnly) {
|
||||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||||
|
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
|
||||||
}
|
}
|
||||||
} else if (visualize) {
|
} else if (visualize) {
|
||||||
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
|
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
|
||||||
|
@@ -15,6 +15,7 @@ async function createServer() {
|
|||||||
|
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(express.static('./packages/mermaid/dist'));
|
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(express.static('./packages/mermaid-example-diagram/dist'));
|
||||||
app.use(vite.middlewares);
|
app.use(vite.middlewares);
|
||||||
app.use(express.static('demos'));
|
app.use(express.static('demos'));
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
"adamiecki",
|
"adamiecki",
|
||||||
"alois",
|
"alois",
|
||||||
"antiscript",
|
"antiscript",
|
||||||
|
"antlr",
|
||||||
"appli",
|
"appli",
|
||||||
"applitools",
|
"applitools",
|
||||||
"asciidoctor",
|
"asciidoctor",
|
||||||
@@ -110,7 +111,8 @@
|
|||||||
"visio",
|
"visio",
|
||||||
"vitepress",
|
"vitepress",
|
||||||
"xlink",
|
"xlink",
|
||||||
"yash"
|
"yash",
|
||||||
|
"zenuml"
|
||||||
],
|
],
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
|
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
|
||||||
|
@@ -63,6 +63,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<h2><a href="./state.html">State</a></h2>
|
<h2><a href="./state.html">State</a></h2>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<h2><a href="./zenuml.html">ZenUML</a></h2>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
53
demos/zenuml.html
Normal file
53
demos/zenuml.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<title>Mermaid Zenuml Test Page</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Zenuml demos</h1>
|
||||||
|
<pre class="mermaid">
|
||||||
|
zenuml
|
||||||
|
title Sync Messages (Design Pattern: Adapter)
|
||||||
|
@Starter(Client)
|
||||||
|
Adapter.interfaceMethod() {
|
||||||
|
translateParameter(parameter)
|
||||||
|
|
||||||
|
result = Implementation.implementationMethod()
|
||||||
|
|
||||||
|
translateResult()
|
||||||
|
return translatedResult
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<pre class="mermaid">
|
||||||
|
zenuml
|
||||||
|
title Async Messages (SPA Authentication)
|
||||||
|
// ```
|
||||||
|
// GET https://${account.namespace}/authorize/?
|
||||||
|
// response_type=token
|
||||||
|
// &client_id=${account.clientId}
|
||||||
|
// &redirect_url=YOUR_CALLBACK_URL
|
||||||
|
// &state=VALUE_THAT_SURVIVES_REDIRECTS
|
||||||
|
// &scope=openid
|
||||||
|
// ```
|
||||||
|
Browser->Auth0: 1. initiate the authentication
|
||||||
|
Auth0->"Identity Provider": 2. OAuth2 / SAML, etc
|
||||||
|
"Identity Provider"->"Identity Provider": 3. user gets authenticated
|
||||||
|
Auth0->Browser: 4. redirect to ${YOUR_CALLBACK_URL}/#id_token=e68...
|
||||||
|
Browser->Auth0: 5. validate id_token and get user profile
|
||||||
|
Browser->"Your API": 6. call API sending JWT in Authorization header
|
||||||
|
"Your API"->"Your API": 7. validate token
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import mermaid from './mermaid.esm.mjs';
|
||||||
|
import zenuml from './mermaid-zenuml.esm.mjs';
|
||||||
|
await mermaid.registerExternalDiagrams([zenuml]);
|
||||||
|
mermaid.initialize({
|
||||||
|
logLevel: 3,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
47
packages/mermaid-zenuml/package.json
Normal file
47
packages/mermaid-zenuml/package.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"name": "@mermaid-js/mermaid-zenuml",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Zenuml integration for MermaidJS.",
|
||||||
|
"module": "dist/mermaid-zenuml.core.mjs",
|
||||||
|
"types": "dist/detector.d.ts",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/mermaid-zenuml.core.mjs",
|
||||||
|
"types": "./dist/detector.d.ts"
|
||||||
|
},
|
||||||
|
"./*": "./*"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"diagram",
|
||||||
|
"markdown",
|
||||||
|
"zenuml",
|
||||||
|
"mermaid"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"prepublishOnly": "pnpm -w run build"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/mermaid-js/mermaid"
|
||||||
|
},
|
||||||
|
"author": "Peng Xiao",
|
||||||
|
"license": "MIT",
|
||||||
|
"standard": {
|
||||||
|
"ignore": [
|
||||||
|
"dist/**/*.js"
|
||||||
|
],
|
||||||
|
"globals": [
|
||||||
|
"page"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@zenuml/core": "^2.0.36"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mermaid": "workspace:*"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
21
packages/mermaid-zenuml/src/detector.ts
Normal file
21
packages/mermaid-zenuml/src/detector.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { ExternalDiagramDefinition } from 'mermaid';
|
||||||
|
|
||||||
|
const id = 'zenuml';
|
||||||
|
const regexp = /^\s*zenuml/;
|
||||||
|
|
||||||
|
const detector = (txt: string) => {
|
||||||
|
return txt.match(regexp) !== null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loader = async () => {
|
||||||
|
const { diagram } = await import('./zenuml-definition.js');
|
||||||
|
return { id, diagram };
|
||||||
|
};
|
||||||
|
|
||||||
|
const plugin: ExternalDiagramDefinition = {
|
||||||
|
id,
|
||||||
|
detector,
|
||||||
|
loader,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default plugin;
|
58
packages/mermaid-zenuml/src/mermaidUtils.ts
Normal file
58
packages/mermaid-zenuml/src/mermaidUtils.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import type { MermaidConfig } from 'mermaid';
|
||||||
|
|
||||||
|
const warning = (s: string) => {
|
||||||
|
// Todo remove debug code
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('Log function was called before initialization', s);
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||||
|
|
||||||
|
export const LEVELS: Record<LogLevel, number> = {
|
||||||
|
trace: 0,
|
||||||
|
debug: 1,
|
||||||
|
info: 2,
|
||||||
|
warn: 3,
|
||||||
|
error: 4,
|
||||||
|
fatal: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||||
|
trace: warning,
|
||||||
|
debug: warning,
|
||||||
|
info: warning,
|
||||||
|
warn: warning,
|
||||||
|
error: warning,
|
||||||
|
fatal: warning,
|
||||||
|
};
|
||||||
|
|
||||||
|
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||||
|
export let getConfig: () => MermaidConfig;
|
||||||
|
export let sanitizeText: (str: string) => string;
|
||||||
|
// eslint-disable @typescript-eslint/no-explicit-any
|
||||||
|
export let setupGraphViewbox: (
|
||||||
|
graph: any,
|
||||||
|
svgElem: any,
|
||||||
|
padding: any,
|
||||||
|
useMaxWidth: boolean
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export const injectUtils = (
|
||||||
|
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
||||||
|
_setLogLevel: any,
|
||||||
|
_getConfig: any,
|
||||||
|
_sanitizeText: any,
|
||||||
|
_setupGraphViewbox: any
|
||||||
|
) => {
|
||||||
|
_log.info('Mermaid utils injected');
|
||||||
|
log.trace = _log.trace;
|
||||||
|
log.debug = _log.debug;
|
||||||
|
log.info = _log.info;
|
||||||
|
log.warn = _log.warn;
|
||||||
|
log.error = _log.error;
|
||||||
|
log.fatal = _log.fatal;
|
||||||
|
setLogLevel = _setLogLevel;
|
||||||
|
getConfig = _getConfig;
|
||||||
|
sanitizeText = _sanitizeText;
|
||||||
|
setupGraphViewbox = _setupGraphViewbox;
|
||||||
|
};
|
10
packages/mermaid-zenuml/src/parser.ts
Normal file
10
packages/mermaid-zenuml/src/parser.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// ZenUML manage parsing internally. It uses Antlr4 to parse the DSL.
|
||||||
|
// The parser is defined in https://github.com/ZenUml/vue-sequence/blob/main/src/parser/index.js
|
||||||
|
|
||||||
|
// This is a dummy parser that satisfies the mermaid API logic.
|
||||||
|
export default {
|
||||||
|
parser: { yy: {} },
|
||||||
|
parse: () => {
|
||||||
|
// no op
|
||||||
|
},
|
||||||
|
};
|
17
packages/mermaid-zenuml/src/zenuml-definition.ts
Normal file
17
packages/mermaid-zenuml/src/zenuml-definition.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { injectUtils } from './mermaidUtils.js';
|
||||||
|
import parser from './parser.js';
|
||||||
|
import renderer from './zenumlRenderer.js';
|
||||||
|
|
||||||
|
export const diagram = {
|
||||||
|
db: {
|
||||||
|
clear: () => {
|
||||||
|
// no-op
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderer,
|
||||||
|
parser,
|
||||||
|
styles: () => {
|
||||||
|
// no-op
|
||||||
|
},
|
||||||
|
injectUtils,
|
||||||
|
};
|
68
packages/mermaid-zenuml/src/zenumlRenderer.ts
Normal file
68
packages/mermaid-zenuml/src/zenumlRenderer.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { getConfig, log } from './mermaidUtils.js';
|
||||||
|
import ZenUml from '@zenuml/core';
|
||||||
|
|
||||||
|
const regexp = /^\s*zenuml/;
|
||||||
|
|
||||||
|
// Create a Zen UML container outside the svg first for rendering, otherwise the Zen UML diagram cannot be rendered properly
|
||||||
|
function createTemporaryZenumlContainer(id: string) {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.id = `container-${id}`;
|
||||||
|
container.style.display = 'flex';
|
||||||
|
container.innerHTML = `<div id="zenUMLApp-${id}"></div>`;
|
||||||
|
const app = container.querySelector(`#zenUMLApp-${id}`) as HTMLElement;
|
||||||
|
return { container, app };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a foreignObject to wrap the Zen UML container in the svg
|
||||||
|
function createForeignObject(id: string) {
|
||||||
|
const foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
|
||||||
|
foreignObject.setAttribute('x', '0');
|
||||||
|
foreignObject.setAttribute('y', '0');
|
||||||
|
foreignObject.setAttribute('width', '100%');
|
||||||
|
foreignObject.setAttribute('height', '100%');
|
||||||
|
const { container, app } = createTemporaryZenumlContainer(id);
|
||||||
|
foreignObject.appendChild(container);
|
||||||
|
return { foreignObject, container, app };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a Zen UML in the tag with id: id based on the graph definition in text.
|
||||||
|
*
|
||||||
|
* @param text - The text of the diagram
|
||||||
|
* @param id - The id of the diagram which will be used as a DOM element id¨
|
||||||
|
*/
|
||||||
|
export const draw = async function (text: string, id: string) {
|
||||||
|
log.info('draw with Zen UML renderer', ZenUml);
|
||||||
|
|
||||||
|
text = text.replace(regexp, '');
|
||||||
|
const { securityLevel } = getConfig();
|
||||||
|
// Handle root and Document for when rendering in sandbox mode
|
||||||
|
let sandboxElement: HTMLIFrameElement | null = null;
|
||||||
|
if (securityLevel === 'sandbox') {
|
||||||
|
sandboxElement = document.getElementById('i' + id) as HTMLIFrameElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = securityLevel === 'sandbox' ? sandboxElement?.contentWindow?.document : document;
|
||||||
|
|
||||||
|
const svgContainer = root?.querySelector(`svg#${id}`);
|
||||||
|
|
||||||
|
if (!root || !svgContainer) {
|
||||||
|
log.error('Cannot find root or svgContainer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { foreignObject, container, app } = createForeignObject(id);
|
||||||
|
svgContainer.appendChild(foreignObject);
|
||||||
|
|
||||||
|
const zenuml = new ZenUml(app);
|
||||||
|
// default is a theme name. More themes to be added and will be configurable in the future
|
||||||
|
await zenuml.render(text, 'theme-mermaid');
|
||||||
|
|
||||||
|
const { width, height } = window.getComputedStyle(container);
|
||||||
|
log.debug('zenuml diagram size', width, height);
|
||||||
|
svgContainer.setAttribute('style', `width: ${width}; height: ${height};`);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
draw,
|
||||||
|
};
|
9
packages/mermaid-zenuml/tsconfig.json
Normal file
9
packages/mermaid-zenuml/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist"
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*.ts"],
|
||||||
|
"typeRoots": ["./src/types"]
|
||||||
|
}
|
514
pnpm-lock.yaml
generated
514
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user