#3061 Log handing and other fixes, error handling in diagram creation

This commit is contained in:
Knut Sveidqvist
2022-09-26 10:44:18 +02:00
parent ebdec77c88
commit a928120bec
10 changed files with 101 additions and 95 deletions

View File

@@ -97,7 +97,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
if (watch && config.build) { if (watch && config.build) {
config.build.watch = { config.build.watch = {
include: 'src/**', include: ['packages/mermaid-mindmap/src/**', 'packages/mermaid/src/**'],
}; };
} }

View File

@@ -45,12 +45,12 @@
</head> </head>
<body> <body>
<div>Security check</div> <div>Security check</div>
<pre id="diagram" class="mermaid2">
flowchart LR
A --> B
</pre>
<pre id="diagram" class="mermaid"> <pre id="diagram" class="mermaid">
mindmap flowchart LR
A -> B
</pre>
<pre id="diagram" class="mermaid2">
mindmap((
root root
ch1 ch1
ch2 ch2
@@ -71,6 +71,10 @@ flowchart LR
function callback() { function callback() {
alert('It worked'); alert('It worked');
} }
mermaid.parseError = function (err, hash) {
console.error('In parse error:');
console.error(err);
};
</script> </script>
</body> </body>
</html> </html>

View File

@@ -29,7 +29,7 @@
"clean": "rimraf dist", "clean": "rimraf dist",
"build:vite": "ts-node-esm --transpileOnly --project=.vite/tsconfig.json .vite/build.ts", "build:vite": "ts-node-esm --transpileOnly --project=.vite/tsconfig.json .vite/build.ts",
"build:types": "concurrently \"tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly\" \"tsc -p ./packages/mermaid-mindmap/tsconfig.json --emitDeclarationOnly\"", "build:types": "concurrently \"tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly\" \"tsc -p ./packages/mermaid-mindmap/tsconfig.json --emitDeclarationOnly\"",
"build:watch": "pnpm build:code --watch", "build:watch": "pnpm build:vite --watch",
"build": "pnpm clean; concurrently \"pnpm build:vite\" \"pnpm build:types\"", "build": "pnpm clean; concurrently \"pnpm build:vite\" \"pnpm build:types\"",
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server\"", "dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server\"",
"docs:build": "ts-node-esm --transpileOnly packages/mermaid/src/docs.mts", "docs:build": "ts-node-esm --transpileOnly packages/mermaid/src/docs.mts",

View File

@@ -41,10 +41,13 @@ export const injectUtils = (
_sanitizeText: any, _sanitizeText: any,
_setupGraphViewbox: any _setupGraphViewbox: any
) => { ) => {
_log.info('Mermaid utils injected');
log.trace = _log.trace;
log.debug = _log.debug; log.debug = _log.debug;
log.info = _log.info; log.info = _log.info;
log.warn = _log.warn; log.warn = _log.warn;
log.error = _log.error; log.error = _log.error;
log.fatal = _log.fatal;
setLogLevel = _setLogLevel; setLogLevel = _setLogLevel;
getConfig = _getConfig; getConfig = _getConfig;
sanitizeText = _sanitizeText; sanitizeText = _sanitizeText;
@@ -55,6 +58,7 @@ export const injectUtils = (
const warning = (..._args: any[]) => { const warning = (..._args: any[]) => {
console.error('Log function was called before initialization'); console.error('Log function was called before initialization');
}; };
export let log = { export let log = {
trace: warning, trace: warning,
debug: warning, debug: warning,

View File

@@ -1,5 +1,5 @@
/** Created by knut on 15-01-14. */ /** Created by knut on 15-01-14. */
import { sanitizeText, getConfig, log as _log } from './mermaidUtils'; import { sanitizeText, getConfig, log } from './mermaidUtils';
let nodes = []; let nodes = [];
let cnt = 0; let cnt = 0;
@@ -131,9 +131,19 @@ export const type2Str = (type) => {
return 'no-border'; return 'no-border';
} }
}; };
export let parseError; // = (str, hash)
// => {
// const error = { str, hash };
// throw error;
// };
export const setErrorHandler = (handler) => {
parseError = handler;
};
// Expose logger to grammar // Expose logger to grammar
export const log = _log; export const getLogger = () => log;
export let graphType = 'mindmap';
export const getNodeById = (id) => nodes[id]; export const getNodeById = (id) => nodes[id];
export const getElementById = (id) => elements[id]; export const getElementById = (id) => elements[id];
// export default { // export default {

View File

@@ -215,51 +215,53 @@ function positionNodes(node, conf) {
* @param {any} version * @param {any} version
* @param diagObj * @param diagObj
*/ */
export const draw = (text, id, version, diagObj) => { export const draw = (text, id, version, diagObj) => {
const conf = getConfig(); const conf = getConfig();
try {
log.debug('Renering info diagram\n' + text);
const securityLevel = getConfig().securityLevel; // This is done only for throwing the error if the text is not valid.
// Handle root and Document for when rendering in sanbox mode diagObj.db.clear();
let sandboxElement; // Parse the graph definition
if (securityLevel === 'sandbox') { diagObj.parser.parse(text);
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
// Parse the graph definition
const svg = root.select('#' + id); log.debug('Renering info diagram\n' + text);
svg.append('g'); const securityLevel = getConfig().securityLevel;
const mm = diagObj.db.getMindmap(); // Handle root and Document for when rendering in sanbox mode
let sandboxElement;
// Draw the graph and start with drawing the nodes without proper position if (securityLevel === 'sandbox') {
// this gives us the size of the nodes and we can set the positions later sandboxElement = select('#i' + id);
const edgesElem = svg.append('g');
edgesElem.attr('class', 'mindmap-edges');
const nodesElem = svg.append('g');
nodesElem.attr('class', 'mindmap-nodes');
drawNodes(nodesElem, mm, -1, conf);
// Next step is to layout the mindmap, giving each node a position
const positionedMindmap = layoutMindmap(mm, conf);
// After this we can draw, first the edges and the then nodes with the correct position
drawEdges(edgesElem, positionedMindmap, null, 0, -1, conf);
positionNodes(positionedMindmap, conf);
// Setup the view box and size of the svg element
setupGraphViewbox(undefined, svg, conf.mindmap.padding, conf.mindmap.useMaxWidth);
} catch (e) {
log.error('Error while rendering info diagram');
log.error(e.message);
} }
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
// Parse the graph definition
const svg = root.select('#' + id);
svg.append('g');
const mm = diagObj.db.getMindmap();
// Draw the graph and start with drawing the nodes without proper position
// this gives us the size of the nodes and we can set the positions later
const edgesElem = svg.append('g');
edgesElem.attr('class', 'mindmap-edges');
const nodesElem = svg.append('g');
nodesElem.attr('class', 'mindmap-nodes');
drawNodes(nodesElem, mm, -1, conf);
// Next step is to layout the mindmap, giving each node a position
const positionedMindmap = layoutMindmap(mm, conf);
// After this we can draw, first the edges and the then nodes with the correct position
drawEdges(edgesElem, positionedMindmap, null, 0, -1, conf);
positionNodes(positionedMindmap, conf);
// Setup the view box and size of the svg element
setupGraphViewbox(undefined, svg, conf.mindmap.padding, conf.mindmap.useMaxWidth);
}; };
export default { export default {

View File

@@ -17,21 +17,21 @@
%% %%
\s*\%\%.* {yy.log.trace('Found comment',yytext);} \s*\%\%.* {yy.getLogger().trace('Found comment',yytext);}
// \%\%[^\n]*\n /* skip comments */ // \%\%[^\n]*\n /* skip comments */
"mindmap" return 'MINDMAP'; "mindmap" return 'MINDMAP';
":::" { this.begin('CLASS'); } ":::" { this.begin('CLASS'); }
<CLASS>.+ { this.popState();return 'CLASS'; } <CLASS>.+ { this.popState();return 'CLASS'; }
<CLASS>\n { this.popState();} <CLASS>\n { this.popState();}
// [\s]*"::icon(" { this.begin('ICON'); } // [\s]*"::icon(" { this.begin('ICON'); }
"::icon(" { yy.log.trace('Begin icon');this.begin('ICON'); } "::icon(" { yy.getLogger().trace('Begin icon');this.begin('ICON'); }
[\n]+ return 'NL'; [\n]+ return 'NL';
<ICON>[^\)]+ { return 'ICON'; } <ICON>[^\)]+ { return 'ICON'; }
<ICON>\) {yy.log.trace('end icon');this.popState();} <ICON>\) {yy.getLogger().trace('end icon');this.popState();}
"-)" { yy.log.trace('Exploding node'); this.begin('NODE');return 'NODE_DSTART'; } "-)" { yy.getLogger().trace('Exploding node'); this.begin('NODE');return 'NODE_DSTART'; }
"(-" { yy.log.trace('Cloud'); this.begin('NODE');return 'NODE_DSTART'; } "(-" { yy.getLogger().trace('Cloud'); this.begin('NODE');return 'NODE_DSTART'; }
"))" { yy.log.trace('Explosion Bang'); this.begin('NODE');return 'NODE_DSTART'; } "))" { yy.getLogger().trace('Explosion Bang'); this.begin('NODE');return 'NODE_DSTART'; }
")" { yy.log.trace('Cloud Bang'); this.begin('NODE');return 'NODE_DSTART'; } ")" { yy.getLogger().trace('Cloud Bang'); this.begin('NODE');return 'NODE_DSTART'; }
"((" { this.begin('NODE');return 'NODE_DSTART'; } "((" { this.begin('NODE');return 'NODE_DSTART'; }
"(" { this.begin('NODE');return 'NODE_DSTART'; } "(" { this.begin('NODE');return 'NODE_DSTART'; }
"[" { this.begin('NODE');return 'NODE_DSTART'; } "[" { this.begin('NODE');return 'NODE_DSTART'; }
@@ -39,18 +39,18 @@
// !(-\() return 'NODE_ID'; // !(-\() return 'NODE_ID';
[^\(\[\n\-\)]+ return 'NODE_ID'; [^\(\[\n\-\)]+ return 'NODE_ID';
<<EOF>> return 'EOF'; <<EOF>> return 'EOF';
<NODE>["] { yy.log.trace('Starting NSTR');this.begin("NSTR");} <NODE>["] { yy.getLogger().trace('Starting NSTR');this.begin("NSTR");}
<NSTR>[^"]+ { yy.log.trace('description:', yytext); return "NODE_DESCR";} <NSTR>[^"]+ { yy.getLogger().trace('description:', yytext); return "NODE_DESCR";}
<NSTR>["] {this.popState();} <NSTR>["] {this.popState();}
<NODE>[\)]\) {this.popState();yy.log.trace('node end ))');return "NODE_DEND";} <NODE>[\)]\) {this.popState();yy.getLogger().trace('node end ))');return "NODE_DEND";}
<NODE>[\)] {this.popState();yy.log.trace('node end )');return "NODE_DEND";} <NODE>[\)] {this.popState();yy.getLogger().trace('node end )');return "NODE_DEND";}
<NODE>[\]] {this.popState();yy.log.trace('node end ...',yytext);return "NODE_DEND";} <NODE>[\]] {this.popState();yy.getLogger().trace('node end ...',yytext);return "NODE_DEND";}
<NODE>"(-" {this.popState();yy.log.trace('node end (-');return "NODE_DEND";} <NODE>"(-" {this.popState();yy.getLogger().trace('node end (-');return "NODE_DEND";}
<NODE>"-)" {this.popState();yy.log.trace('node end (-');return "NODE_DEND";} <NODE>"-)" {this.popState();yy.getLogger().trace('node end (-');return "NODE_DEND";}
<NODE>"((" {this.popState();yy.log.trace('node end ((');return "NODE_DEND";} <NODE>"((" {this.popState();yy.getLogger().trace('node end ((');return "NODE_DEND";}
<NODE>"(" {this.popState();yy.log.trace('node end ((');return "NODE_DEND";} <NODE>"(" {this.popState();yy.getLogger().trace('node end ((');return "NODE_DEND";}
<NODE>[^\)\]\(]+ { yy.log.trace('Long description:', yytext); return 'NODE_DESCR';} <NODE>[^\)\]\(]+ { yy.getLogger().trace('Long description:', yytext); return 'NODE_DESCR';}
<NODE>.+(?!\(\() { yy.log.trace('Long description:', yytext); return 'NODE_DESCR';} <NODE>.+(?!\(\() { yy.getLogger().trace('Long description:', yytext); return 'NODE_DESCR';}
// [\[] return 'NODE_START'; // [\[] return 'NODE_START';
// .+ return 'TXT' ; // .+ return 'TXT' ;
@@ -68,10 +68,10 @@ start
; ;
stop stop
: NL {yy.log.trace('Stop NL ');} : NL {yy.getLogger().trace('Stop NL ');}
| EOF {yy.log.trace('Stop EOF ');} | EOF {yy.getLogger().trace('Stop EOF ');}
| stop NL {yy.log.trace('Stop NL2 ');} | stop NL {yy.getLogger().trace('Stop NL2 ');}
| stop EOF {yy.log.trace('Stop EOF2 ');} | stop EOF {yy.getLogger().trace('Stop EOF2 ');}
; ;
document document
: document statement stop : document statement stop
@@ -79,10 +79,10 @@ document
; ;
statement statement
: SPACELIST node { yy.log.trace('Node: ',$2.id);yy.addNode($1.length, $2.id, $2.descr, $2.type); } : SPACELIST node { yy.getLogger().trace('Node: ',$2.id);yy.addNode($1.length, $2.id, $2.descr, $2.type); }
| SPACELIST ICON { yy.log.trace('Icon: ',$2);yy.decorateNode({icon: $2}); } | SPACELIST ICON { yy.getLogger().trace('Icon: ',$2);yy.decorateNode({icon: $2}); }
| SPACELIST CLASS { yy.decorateNode({class: $2}); } | SPACELIST CLASS { yy.decorateNode({class: $2}); }
| node { yy.log.trace('Node: ',$1.id);yy.addNode(0, $1.id, $1.descr, $1.type); } | node { yy.getLogger().trace('Node: ',$1.id);yy.addNode(0, $1.id, $1.descr, $1.type); }
| ICON { yy.decorateNode({icon: $1}); } | ICON { yy.decorateNode({icon: $1}); }
| CLASS { yy.decorateNode({class: $1}); } | CLASS { yy.decorateNode({class: $1}); }
| SPACELIST | SPACELIST
@@ -97,12 +97,12 @@ node
nodeWithoutId nodeWithoutId
: NODE_DSTART NODE_DESCR NODE_DEND : NODE_DSTART NODE_DESCR NODE_DEND
{ yy.log.trace("node found ..", $1); $$ = { id: $2, descr: $2, type: yy.getType($1, $3) }; } { yy.getLogger().trace("node found ..", $1); $$ = { id: $2, descr: $2, type: yy.getType($1, $3) }; }
; ;
nodeWithId nodeWithId
: NODE_ID { $$ = { id: $1, descr: $1, type: yy.nodeType.DEFAULT }; } : NODE_ID { $$ = { id: $1, descr: $1, type: yy.nodeType.DEFAULT }; }
| NODE_ID NODE_DSTART NODE_DESCR NODE_DEND | NODE_ID NODE_DSTART NODE_DESCR NODE_DEND
{ yy.log.trace("node found ..", $1); $$ = { id: $1, descr: $3, type: yy.getType($2, $4) }; } { yy.getLogger().trace("node found ..", $1); $$ = { id: $1, descr: $3, type: yy.getType($2, $4) }; }
; ;
%% %%

View File

@@ -5,10 +5,10 @@ if (typeof document !== 'undefined') {
if (window.mermaid && typeof window.mermaid.detectors === 'object') { if (window.mermaid && typeof window.mermaid.detectors === 'object') {
window.mermaid.detectors.push({ id: 'mindmap', detector: mindmapDetector }); window.mermaid.detectors.push({ id: 'mindmap', detector: mindmapDetector });
} else { } else {
console.error('window.mermaid.detectors not found'); // eslint-disable-line no-console // console.error('window.mermaid.detectors was not found!'); // eslint-disable-line no-console
window.mermaid = {}; window.mermaid = {};
window.mermaid.detectors = [{ id: 'mindmap', detector: mindmapDetector }]; window.mermaid.detectors = [{ id: 'mindmap', detector: mindmapDetector }];
console.error('Detectors now:', window.mermaid.detectors); // eslint-disable-line no-console // console.error('Detectors now:', window.mermaid.detectors); // eslint-disable-line no-console
} }
/*! /*!

View File

@@ -15,33 +15,19 @@ export class Diagram {
this.type = detectType(txt, cnf); this.type = detectType(txt, cnf);
const diagram = getDiagram(this.type); const diagram = getDiagram(this.type);
log.debug('Type ' + this.type); log.debug('Type ' + this.type);
// console.log('Type ' + this.type);
// Setup diagram // Setup diagram
this.db = diagram.db; this.db = diagram.db;
this.db.clear?.(); this.db.clear?.();
this.renderer = diagram.renderer; this.renderer = diagram.renderer;
this.parser = diagram.parser; this.parser = diagram.parser;
// console.log('Setting db to !', this.db);
this.parser.parser.yy = this.db; this.parser.parser.yy = this.db;
if (diagram.init) { if (diagram.init) {
diagram.init(cnf); diagram.init(cnf);
log.debug('Initialized diagram ' + this.type, cnf); log.debug('Initialized diagram ' + this.type, cnf);
} }
this.txt += '\n'; this.txt += '\n';
try {
this.parser.parser.yy.graphType = this.type; this.parse(this.txt, parseError);
this.parser.parser.yy.parseError = (str: string, hash: string) => {
const error = { str, hash };
throw error;
};
} catch (error) {
log.error('error', error);
}
try {
this.parse(this.txt, parseError);
} catch (error) {
log.error('error', error);
}
} }
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types

View File

@@ -53,7 +53,7 @@ const init = function (
callback?: Function callback?: Function
) { ) {
try { try {
console.error('Detectors in init', mermaid.detectors); // eslint-disable-line log.info('Detectors in init', mermaid.detectors); // eslint-disable-line
mermaid.detectors.forEach(({ id, detector }) => { mermaid.detectors.forEach(({ id, detector }) => {
addDetector(id, detector); addDetector(id, detector);
}); });