mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 14:29:25 +02:00
tsConversion: mermaid main
This commit is contained in:
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
||||
demos/*.html
|
@@ -6,7 +6,7 @@ export default {
|
||||
amd: false, // https://github.com/lodash/lodash/issues/3052
|
||||
target: 'web',
|
||||
entry: {
|
||||
mermaid: './src/mermaid.ts',
|
||||
mermaid: './src/mermaid',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.jison'],
|
||||
|
@@ -4,7 +4,7 @@ import { merge } from 'webpack-merge';
|
||||
export default merge(baseConfig, {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
mermaid: './src/mermaid.ts',
|
||||
mermaid: './src/mermaid',
|
||||
e2e: './cypress/platform/viewer.js',
|
||||
'bundle-test': './cypress/platform/bundle-test.js',
|
||||
},
|
||||
|
@@ -31,6 +31,7 @@
|
||||
"lint:fix": "yarn lint --fix",
|
||||
"e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js",
|
||||
"cypress": "cypress run",
|
||||
"cypress:open": "cypress open",
|
||||
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
|
||||
"e2e-upd": "yarn lint && jest e2e -u --config e2e/jest.config.js",
|
||||
"dev": "webpack serve --config ./.webpack/webpack.config.e2e.babel.js",
|
||||
@@ -129,4 +130,4 @@
|
||||
"**/*.css",
|
||||
"**/*.scss"
|
||||
]
|
||||
}
|
||||
}
|
1
src/@types/config.d.ts
vendored
1
src/@types/config.d.ts
vendored
@@ -8,6 +8,7 @@ export interface MermaidConfig {
|
||||
themeCSS?: string;
|
||||
maxTextSize?: number;
|
||||
darkMode?: boolean;
|
||||
htmlLabels?: boolean;
|
||||
fontFamily?: string;
|
||||
logLevel?: number;
|
||||
securityLevel?: string;
|
||||
|
@@ -2,16 +2,17 @@ import assignWithDepth from './assignWithDepth';
|
||||
import { log } from './logger';
|
||||
import theme from './themes';
|
||||
import config from './defaultConfig';
|
||||
import { MermaidConfig } from 'types/config';
|
||||
|
||||
export const defaultConfig = Object.freeze(config);
|
||||
export const defaultConfig: MermaidConfig = Object.freeze(config);
|
||||
|
||||
let siteConfig = assignWithDepth({}, defaultConfig);
|
||||
let configFromInitialize;
|
||||
let directives = [];
|
||||
let currentConfig = assignWithDepth({}, defaultConfig);
|
||||
let siteConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
|
||||
let configFromInitialize: MermaidConfig;
|
||||
let directives: any[] = [];
|
||||
let currentConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
|
||||
|
||||
export const updateCurrentConfig = (siteCfg, _directives) => {
|
||||
// start with config beeing the siteConfig
|
||||
export const updateCurrentConfig = (siteCfg: MermaidConfig, _directives: any[]) => {
|
||||
// start with config being the siteConfig
|
||||
let cfg = assignWithDepth({}, siteCfg);
|
||||
// let sCfg = assignWithDepth(defaultConfig, siteConfigDelta);
|
||||
|
||||
@@ -27,12 +28,15 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
|
||||
|
||||
cfg = assignWithDepth(cfg, sumOfDirectives);
|
||||
|
||||
// @ts-ignore
|
||||
if (sumOfDirectives.theme && theme[sumOfDirectives.theme]) {
|
||||
const tmpConfigFromInitialize = assignWithDepth({}, configFromInitialize);
|
||||
const themeVariables = assignWithDepth(
|
||||
tmpConfigFromInitialize.themeVariables || {},
|
||||
// @ts-ignore
|
||||
sumOfDirectives.themeVariables
|
||||
);
|
||||
// @ts-ignore
|
||||
cfg.themeVariables = theme[cfg.theme].getThemeVariables(themeVariables);
|
||||
}
|
||||
|
||||
@@ -55,11 +59,13 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
|
||||
* @param conf - The base currentConfig to use as siteConfig
|
||||
* @returns {object} - The siteConfig
|
||||
*/
|
||||
export const setSiteConfig = (conf) => {
|
||||
export const setSiteConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||
siteConfig = assignWithDepth({}, defaultConfig);
|
||||
siteConfig = assignWithDepth(siteConfig, conf);
|
||||
|
||||
// @ts-ignore
|
||||
if (conf.theme && theme[conf.theme]) {
|
||||
// @ts-ignore
|
||||
siteConfig.themeVariables = theme[conf.theme].getThemeVariables(conf.themeVariables);
|
||||
}
|
||||
|
||||
@@ -67,11 +73,11 @@ export const setSiteConfig = (conf) => {
|
||||
return siteConfig;
|
||||
};
|
||||
|
||||
export const saveConfigFromInitialize = (conf) => {
|
||||
export const saveConfigFromInitialize = (conf: MermaidConfig): void => {
|
||||
configFromInitialize = assignWithDepth({}, conf);
|
||||
};
|
||||
|
||||
export const updateSiteConfig = (conf) => {
|
||||
export const updateSiteConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||
siteConfig = assignWithDepth(siteConfig, conf);
|
||||
updateCurrentConfig(siteConfig, directives);
|
||||
|
||||
@@ -88,7 +94,7 @@ export const updateSiteConfig = (conf) => {
|
||||
*
|
||||
* @returns {object} - The siteConfig
|
||||
*/
|
||||
export const getSiteConfig = () => {
|
||||
export const getSiteConfig = (): MermaidConfig => {
|
||||
return assignWithDepth({}, siteConfig);
|
||||
};
|
||||
/**
|
||||
@@ -105,7 +111,7 @@ export const getSiteConfig = () => {
|
||||
* @param {any} conf - The potential currentConfig
|
||||
* @returns {any} - The currentConfig merged with the sanitized conf
|
||||
*/
|
||||
export const setConfig = (conf) => {
|
||||
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||
// sanitize(conf);
|
||||
// Object.keys(conf).forEach(key => {
|
||||
// const manipulator = manipulators[key];
|
||||
@@ -143,17 +149,14 @@ export const getConfig = () => {
|
||||
*
|
||||
* @param {any} options - The potential setConfig parameter
|
||||
*/
|
||||
export const sanitize = (options) => {
|
||||
export const sanitize = (options: any) => {
|
||||
// Checking that options are not in the list of excluded options
|
||||
Object.keys(siteConfig.secure).forEach((key) => {
|
||||
if (typeof options[siteConfig.secure[key]] !== 'undefined') {
|
||||
// DO NOT attempt to print options[siteConfig.secure[key]] within `${}` as a malicious script
|
||||
siteConfig.secure?.forEach((key) => {
|
||||
if (typeof options[key] !== 'undefined') {
|
||||
// DO NOT attempt to print options[key] within `${}` as a malicious script
|
||||
// can exploit the logger's attempt to stringify the value and execute arbitrary code
|
||||
log.debug(
|
||||
`Denied attempt to modify a secure key ${siteConfig.secure[key]}`,
|
||||
options[siteConfig.secure[key]]
|
||||
);
|
||||
delete options[siteConfig.secure[key]];
|
||||
log.debug(`Denied attempt to modify a secure key ${key}`, options[key]);
|
||||
delete options[key];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -186,7 +189,7 @@ export const sanitize = (options) => {
|
||||
*
|
||||
* @param {object} directive The directive to push in
|
||||
*/
|
||||
export const addDirective = (directive) => {
|
||||
export const addDirective = (directive: any) => {
|
||||
if (directive.fontFamily) {
|
||||
if (!directive.themeVariables) {
|
||||
directive.themeVariables = { fontFamily: directive.fontFamily };
|
||||
@@ -215,7 +218,7 @@ export const addDirective = (directive) => {
|
||||
*
|
||||
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
|
||||
*/
|
||||
export const reset = () => {
|
||||
export const reset = (): void => {
|
||||
// Replace current config with siteConfig
|
||||
directives = [];
|
||||
updateCurrentConfig(siteConfig, directives);
|
@@ -40,10 +40,10 @@ const diagramMatchers: Record<string, RegExp> = {
|
||||
* class: { defaultRenderer: string } | undefined;
|
||||
* state: { defaultRenderer: string } | undefined;
|
||||
* flowchart: { defaultRenderer: string } | undefined;
|
||||
* }} [cnf]
|
||||
* }} [config]
|
||||
* @returns {string} A graph definition key
|
||||
*/
|
||||
export const detectType = function (text: string, cnf: MermaidConfig): string {
|
||||
export const detectType = function (text: string, config?: MermaidConfig): string {
|
||||
text = text.replace(directive, '').replace(anyComment, '\n');
|
||||
for (const [diagram, matcher] of Object.entries(diagramMatchers)) {
|
||||
if (text.match(matcher)) {
|
||||
@@ -52,16 +52,16 @@ export const detectType = function (text: string, cnf: MermaidConfig): string {
|
||||
}
|
||||
|
||||
if (text.match(/^\s*classDiagram/)) {
|
||||
if (cnf?.class?.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
|
||||
if (config?.class?.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
|
||||
return 'class';
|
||||
}
|
||||
|
||||
if (text.match(/^\s*stateDiagram/)) {
|
||||
if (cnf?.state?.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
|
||||
if (config?.state?.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
|
||||
return 'state';
|
||||
}
|
||||
|
||||
if (cnf?.flowchart?.defaultRenderer === 'dagre-wrapper') {
|
||||
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
|
||||
return 'flowchart-v2';
|
||||
}
|
||||
|
||||
|
126
src/mermaid.ts
126
src/mermaid.ts
@@ -1,9 +1,8 @@
|
||||
// TODO: Remove
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* Web page integration module for the mermaid framework. It uses the mermaidAPI for mermaid
|
||||
* functionality and to render the diagrams to svg code.
|
||||
*/
|
||||
import { MermaidConfig } from 'types/config';
|
||||
import { log } from './logger';
|
||||
import mermaidAPI from './mermaidAPI';
|
||||
import utils from './utils';
|
||||
@@ -31,73 +30,73 @@ import utils from './utils';
|
||||
*
|
||||
* Renders the mermaid diagrams
|
||||
*/
|
||||
const init = function (config: any, ...nodes: any[]) {
|
||||
const init = function (
|
||||
config?: MermaidConfig,
|
||||
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
|
||||
callback?: Function
|
||||
) {
|
||||
try {
|
||||
initThrowsErrors(config, nodes);
|
||||
initThrowsErrors(config, nodes, callback);
|
||||
} catch (e) {
|
||||
log.warn('Syntax Error rendering');
|
||||
// @ts-ignore
|
||||
log.warn(e.str);
|
||||
if (this.parseError) {
|
||||
this.parseError(e);
|
||||
if (mermaid.parseError) {
|
||||
// @ts-ignore
|
||||
mermaid.parseError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const initThrowsErrors = function (config: any, nodes: any[]) {
|
||||
const initThrowsErrors = function (
|
||||
config?: MermaidConfig,
|
||||
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
|
||||
callback?: Function
|
||||
) {
|
||||
const conf = mermaidAPI.getConfig();
|
||||
// console.log('Starting rendering diagrams (init) - mermaid.init', conf);
|
||||
if (config) {
|
||||
// @ts-ignore
|
||||
mermaid.sequenceConfig = config;
|
||||
}
|
||||
|
||||
// if last argument is a function this is the callback function
|
||||
let callback: (id: string) => void;
|
||||
if (typeof nodes[nodes.length - 1] === 'function') {
|
||||
callback = nodes[nodes.length - 1];
|
||||
log.debug('Callback function found');
|
||||
|
||||
if (!callback && typeof conf?.mermaid?.callback === 'function') {
|
||||
callback = conf.mermaid.callback;
|
||||
}
|
||||
log.debug(`${!callback ? 'No ' : ''}Callback function found`);
|
||||
let nodesToProcess: NodeListOf<HTMLElement>;
|
||||
if (typeof nodes === 'undefined') {
|
||||
nodesToProcess = document.querySelectorAll('.mermaid');
|
||||
} else if (typeof nodes === 'string') {
|
||||
nodesToProcess = document.querySelectorAll(nodes);
|
||||
} else if (nodes instanceof HTMLElement) {
|
||||
nodesToProcess = new NodeList() as NodeListOf<HTMLElement>;
|
||||
nodesToProcess[0] = nodes;
|
||||
} else if (nodes instanceof NodeList) {
|
||||
nodesToProcess = nodes;
|
||||
} else {
|
||||
if (typeof conf.mermaid !== 'undefined') {
|
||||
if (typeof conf.mermaid.callback === 'function') {
|
||||
callback = conf.mermaid.callback;
|
||||
log.debug('Callback function found');
|
||||
} else {
|
||||
log.debug('No Callback function found');
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes =
|
||||
nodes === undefined
|
||||
? document.querySelectorAll('.mermaid')
|
||||
: typeof nodes === 'string'
|
||||
? document.querySelectorAll(nodes)
|
||||
: nodes instanceof window.Node
|
||||
? [nodes]
|
||||
: nodes; // Last case - sequence config was passed pick next
|
||||
|
||||
log.debug('Start On Load before: ' + mermaid.startOnLoad);
|
||||
if (typeof mermaid.startOnLoad !== 'undefined') {
|
||||
log.debug('Start On Load inner: ' + mermaid.startOnLoad);
|
||||
mermaidAPI.updateSiteConfig({ startOnLoad: mermaid.startOnLoad });
|
||||
throw new Error('Invalid argument nodes for mermaid.init');
|
||||
}
|
||||
|
||||
if (typeof mermaid.ganttConfig !== 'undefined') {
|
||||
mermaidAPI.updateSiteConfig({ gantt: mermaid.ganttConfig });
|
||||
log.debug(`Found ${nodesToProcess.length} diagrams`);
|
||||
if (typeof config?.startOnLoad !== 'undefined') {
|
||||
log.debug('Start On Load: ' + config?.startOnLoad);
|
||||
mermaidAPI.updateSiteConfig({ startOnLoad: config?.startOnLoad });
|
||||
}
|
||||
|
||||
const idGenerator = new utils.initIdGenerator(conf.deterministicIds, conf.deterministicIDSeed);
|
||||
|
||||
let txt;
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
// element is the current div with mermaid class
|
||||
const element = nodes[i];
|
||||
|
||||
// element is the current div with mermaid class
|
||||
for (const element of Array.from(nodesToProcess)) {
|
||||
/*! Check if previously processed */
|
||||
if (!element.getAttribute('data-processed')) {
|
||||
element.setAttribute('data-processed', true);
|
||||
} else {
|
||||
if (element.getAttribute('data-processed')) {
|
||||
continue;
|
||||
}
|
||||
element.setAttribute('data-processed', 'true');
|
||||
|
||||
const id = `mermaid-${idGenerator.next()}`;
|
||||
|
||||
@@ -118,7 +117,7 @@ const initThrowsErrors = function (config: any, nodes: any[]) {
|
||||
mermaidAPI.render(
|
||||
id,
|
||||
txt,
|
||||
(svgCode, bindFunctions) => {
|
||||
(svgCode: string, bindFunctions: (el: HTMLElement) => void) => {
|
||||
element.innerHTML = svgCode;
|
||||
if (typeof callback !== 'undefined') {
|
||||
callback(id);
|
||||
@@ -129,24 +128,15 @@ const initThrowsErrors = function (config: any, nodes: any[]) {
|
||||
);
|
||||
} catch (error) {
|
||||
log.warn('Catching Error (bootstrap)');
|
||||
// @ts-ignore
|
||||
// TODO: We should be throwing an error object.
|
||||
throw { error, message: error.str };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const initialize = function (config: any) {
|
||||
// mermaidAPI.reset();
|
||||
if (typeof config.mermaid !== 'undefined') {
|
||||
if (typeof config.mermaid.startOnLoad !== 'undefined') {
|
||||
mermaid.startOnLoad = config.mermaid.startOnLoad;
|
||||
}
|
||||
if (typeof config.mermaid.htmlLabels !== 'undefined') {
|
||||
mermaid.htmlLabels =
|
||||
config.mermaid.htmlLabels === 'false' || config.mermaid.htmlLabels === false ? false : true;
|
||||
}
|
||||
}
|
||||
const initialize = function (config: MermaidConfig) {
|
||||
mermaidAPI.initialize(config);
|
||||
// mermaidAPI.reset();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,22 +144,9 @@ const initialize = function (config: any) {
|
||||
* configuration for mermaid rendering and calls init for rendering the mermaid diagrams on the page.
|
||||
*/
|
||||
const contentLoaded = function () {
|
||||
let config;
|
||||
|
||||
if (mermaid.startOnLoad) {
|
||||
// No config found, do check API config
|
||||
config = mermaidAPI.getConfig();
|
||||
if (config.startOnLoad) {
|
||||
mermaid.init();
|
||||
}
|
||||
} else {
|
||||
if (typeof mermaid.startOnLoad === 'undefined') {
|
||||
log.debug('In start, no config');
|
||||
config = mermaidAPI.getConfig();
|
||||
if (config.startOnLoad) {
|
||||
mermaid.init();
|
||||
}
|
||||
}
|
||||
const { startOnLoad } = mermaidAPI.getConfig();
|
||||
if (startOnLoad) {
|
||||
mermaid.init();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -200,13 +177,12 @@ if (typeof document !== 'undefined') {
|
||||
*
|
||||
* @param {function (err, hash)} newParseErrorHandler New parseError() callback.
|
||||
*/
|
||||
const setParseErrorHandler = function (newParseErrorHandler) {
|
||||
const setParseErrorHandler = function (newParseErrorHandler: (err: any, hash: any) => void) {
|
||||
// @ts-ignore
|
||||
mermaid.parseError = newParseErrorHandler;
|
||||
};
|
||||
|
||||
const mermaid = {
|
||||
startOnLoad: true,
|
||||
htmlLabels: true,
|
||||
diagrams: {},
|
||||
mermaidAPI,
|
||||
parse: mermaidAPI != undefined ? mermaidAPI.parse : null,
|
||||
@@ -215,7 +191,7 @@ const mermaid = {
|
||||
init,
|
||||
initThrowsErrors,
|
||||
initialize,
|
||||
|
||||
parseError: undefined,
|
||||
contentLoaded,
|
||||
|
||||
setParseErrorHandler,
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
import {
|
||||
curveBasis,
|
||||
@@ -18,6 +19,7 @@ import { configKeys } from './defaultConfig';
|
||||
import { log } from './logger';
|
||||
import { detectType } from './diagram-api/detectType';
|
||||
import assignWithDepth from './assignWithDepth';
|
||||
import { MermaidConfig } from 'types/config';
|
||||
|
||||
// Effectively an enum of the supported curve types, accessible by name
|
||||
const d3CurveTypes = {
|
||||
@@ -71,7 +73,7 @@ const anyComment = /\s*%%.*\n/gm;
|
||||
* @param {any} cnf
|
||||
* @returns {object} The json object representing the init passed to mermaid.initialize()
|
||||
*/
|
||||
export const detectInit = function (text, cnf) {
|
||||
export const detectInit = function (text: string, config?: MermaidConfig): MermaidConfig {
|
||||
let inits = detectDirective(text, /(?:init\b)|(?:initialize\b)/);
|
||||
let results = {};
|
||||
|
||||
@@ -84,7 +86,7 @@ export const detectInit = function (text, cnf) {
|
||||
results = inits.args;
|
||||
}
|
||||
if (results) {
|
||||
let type = detectType(text, cnf);
|
||||
let type = detectType(text, config);
|
||||
['config'].forEach((prop) => {
|
||||
if (typeof results[prop] !== 'undefined') {
|
||||
if (type === 'flowchart-v2') {
|
Reference in New Issue
Block a user