mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-29 00:54:08 +01:00
Merge branch 'release/10.2.4'
This commit is contained in:
@@ -52,9 +52,6 @@
|
||||
"rimraf": "^5.0.0",
|
||||
"mermaid": "workspace:*"
|
||||
},
|
||||
"resolutions": {
|
||||
"d3": "^7.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
const id = 'example-diagram';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*example-diagram/) !== null;
|
||||
return /^\s*example-diagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
|
||||
const id = 'zenuml';
|
||||
const regexp = /^\s*zenuml/;
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(regexp) !== null;
|
||||
return /^\s*zenuml/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "10.2.3",
|
||||
"version": "10.2.4",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -73,6 +73,7 @@
|
||||
"devDependencies": {
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-selection": "^3.0.5",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
@@ -91,7 +92,7 @@
|
||||
"globby": "^13.1.4",
|
||||
"jison": "^0.4.18",
|
||||
"js-base64": "^3.7.5",
|
||||
"jsdom": "^21.1.1",
|
||||
"jsdom": "^22.0.0",
|
||||
"micromatch": "^4.0.5",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
|
||||
@@ -51,7 +51,6 @@ describe('accessibility', () => {
|
||||
desc: string | null | undefined,
|
||||
givenId: string
|
||||
) {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
|
||||
@@ -63,7 +62,6 @@ describe('accessibility', () => {
|
||||
desc: string | null | undefined,
|
||||
givenId: string
|
||||
) {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* of src to dst in order.
|
||||
* @param {any} dst - The destination of the merge
|
||||
* @param {any} src - The source object(s) to merge into destination
|
||||
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
|
||||
* @param {{ depth: number; clobber: boolean }} [config] - Depth: depth
|
||||
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
|
||||
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
|
||||
* @returns {any}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Cluster handling
|
||||
|
||||
Dagre does not support edges between nodes and clusters or between clusters to other clusters. In order to remedy this shortcoming the dagre wrapper implements a few work-arounds.
|
||||
Dagre does not support edges between nodes and clusters or between clusters to other clusters. In order to remedy this shortcoming the dagre wrapper implements a few workarounds.
|
||||
|
||||
In the diagram below there are two clusters and there are no edges to nodes outside the own cluster.
|
||||
|
||||
@@ -73,7 +73,7 @@ Sample object:
|
||||
}
|
||||
```
|
||||
|
||||
This is set by the renderer of the diagram and insert the data that the wrapper neds for rendering.
|
||||
This is set by the renderer of the diagram and insert the data that the wrapper needs for rendering.
|
||||
|
||||
| property | description |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------ |
|
||||
@@ -114,7 +114,7 @@ Required edgeData for proper rendering:
|
||||
| label | overlap between label and labelText? |
|
||||
| labelPos | |
|
||||
| labelType | overlap between label and labelText? |
|
||||
| thickness | Sets the thinkess of the edge. Can be \['normal', 'thick'\] |
|
||||
| thickness | Sets the thickness of the edge. Can be \['normal', 'thick'\] |
|
||||
| pattern | Sets the pattern of the edge. Can be \['solid', 'dotted', 'dashed'\] |
|
||||
|
||||
# Markers
|
||||
|
||||
@@ -602,6 +602,8 @@ const doublecircle = async (parent, node) => {
|
||||
const outerCircle = circleGroup.insert('circle');
|
||||
const innerCircle = circleGroup.insert('circle');
|
||||
|
||||
circleGroup.attr('class', node.class);
|
||||
|
||||
// center the circle around its coordinate
|
||||
outerCircle
|
||||
.attr('style', node.style)
|
||||
|
||||
@@ -4,7 +4,7 @@ import flowchartV2 from '../diagrams/flowchart/flowDetector-v2.js';
|
||||
import er from '../diagrams/er/erDetector.js';
|
||||
import git from '../diagrams/git/gitGraphDetector.js';
|
||||
import gantt from '../diagrams/gantt/ganttDetector.js';
|
||||
import info from '../diagrams/info/infoDetector.js';
|
||||
import { info } from '../diagrams/info/infoDetector.js';
|
||||
import pie from '../diagrams/pie/pieDetector.js';
|
||||
import quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js';
|
||||
import requirement from '../diagrams/requirement/requirementDetector.js';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DiagramDb } from './types.js';
|
||||
import { DiagramDB } from './types.js';
|
||||
// The "* as yaml" part is necessary for tree-shaking
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
@@ -22,7 +22,7 @@ type FrontMatterMetadata = {
|
||||
* @param db - Diagram database, could be of any diagram.
|
||||
* @returns text with frontmatter stripped out
|
||||
*/
|
||||
export function extractFrontMatter(text: string, db: DiagramDb): string {
|
||||
export function extractFrontMatter(text: string, db: DiagramDB): string {
|
||||
const matches = text.match(frontMatterRegex);
|
||||
if (matches) {
|
||||
const parsed: FrontMatterMetadata = yaml.load(matches[1], {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Diagram } from '../Diagram.js';
|
||||
import { MermaidConfig } from '../config.type.js';
|
||||
import type * as d3 from 'd3';
|
||||
|
||||
export interface InjectUtils {
|
||||
_log: any;
|
||||
@@ -13,7 +15,7 @@ export interface InjectUtils {
|
||||
/**
|
||||
* Generic Diagram DB that may apply to any diagram type.
|
||||
*/
|
||||
export interface DiagramDb {
|
||||
export interface DiagramDB {
|
||||
clear?: () => void;
|
||||
setDiagramTitle?: (title: string) => void;
|
||||
setDisplayMode?: (title: string) => void;
|
||||
@@ -23,10 +25,10 @@ export interface DiagramDb {
|
||||
}
|
||||
|
||||
export interface DiagramDefinition {
|
||||
db: DiagramDb;
|
||||
db: DiagramDB;
|
||||
renderer: any;
|
||||
parser: any;
|
||||
styles: any;
|
||||
styles?: any;
|
||||
init?: (config: MermaidConfig) => void;
|
||||
injectUtils?: (
|
||||
_log: InjectUtils['_log'],
|
||||
@@ -52,3 +54,33 @@ export interface ExternalDiagramDefinition {
|
||||
|
||||
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
|
||||
export type DiagramLoader = () => Promise<{ id: string; diagram: DiagramDefinition }>;
|
||||
|
||||
/**
|
||||
* Type for function draws diagram 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.
|
||||
* @param version - MermaidJS version from package.json.
|
||||
* @param diagramObject - A standard diagram containing the DB and the text and type etc of the diagram.
|
||||
*/
|
||||
export type DrawDefinition = (
|
||||
text: string,
|
||||
id: string,
|
||||
version: string,
|
||||
diagramObject: Diagram
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Type for function parse directive from diagram code.
|
||||
*
|
||||
* @param statement -
|
||||
* @param context -
|
||||
* @param type -
|
||||
*/
|
||||
export type ParseDirectiveDefinition = (statement: string, context: string, type: string) => void;
|
||||
|
||||
export type HTML = d3.Selection<HTMLIFrameElement, unknown, Element, unknown>;
|
||||
|
||||
export type SVG = d3.Selection<SVGSVGElement, unknown, Element, unknown>;
|
||||
|
||||
export type DiagramStylesProvider = (options?: any) => string;
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'c4';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./c4Diagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -220,7 +220,7 @@ export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray,
|
||||
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
|
||||
c4ShapeTypeConf.fontSize = c4ShapeTypeConf.fontSize - 2;
|
||||
c4Shape.typeC4Shape.width = calculateTextWidth(
|
||||
'<<' + c4Shape.typeC4Shape.text + '>>',
|
||||
'«' + c4Shape.typeC4Shape.text + '»',
|
||||
c4ShapeTypeConf
|
||||
);
|
||||
c4Shape.typeC4Shape.height = c4ShapeTypeConf.fontSize + 2;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-expect-error - d3 types issue
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select, Selection } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import * as configApi from '../../config.js';
|
||||
@@ -367,7 +367,6 @@ export const relationType = {
|
||||
const setupToolTips = function (element: Element) {
|
||||
let tooltipElem: Selection<HTMLDivElement, unknown, HTMLElement, unknown> =
|
||||
select('.mermaidTooltip');
|
||||
// @ts-ignore - _groups is a dynamic property
|
||||
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
||||
tooltipElem = select('body').append('div').attr('class', 'mermaidTooltip').style('opacity', 0);
|
||||
}
|
||||
@@ -449,9 +448,8 @@ const getNamespaces = function (): NamespaceMap {
|
||||
export const addClassesToNamespace = function (id: string, classNames: string[]) {
|
||||
if (namespaces[id] !== undefined) {
|
||||
classNames.map((className) => {
|
||||
classes[className].parent = id;
|
||||
namespaces[id].classes[className] = classes[className];
|
||||
delete classes[className];
|
||||
classCounter--;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'classDiagram';
|
||||
|
||||
const detector: DiagramDetector = (txt, config) => {
|
||||
// If we have configured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
|
||||
if (
|
||||
txt.match(/^\s*classDiagram/) !== null &&
|
||||
config?.class?.defaultRenderer === 'dagre-wrapper'
|
||||
) {
|
||||
if (/^\s*classDiagram/.test(txt) && config?.class?.defaultRenderer === 'dagre-wrapper') {
|
||||
return true;
|
||||
}
|
||||
// We have not opted to use the new renderer so we should return true if we detect a class diagram
|
||||
return txt.match(/^\s*classDiagram-v2/) !== null;
|
||||
return /^\s*classDiagram-v2/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./classDiagram-v2.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'class';
|
||||
|
||||
@@ -8,10 +12,10 @@ const detector: DiagramDetector = (txt, config) => {
|
||||
return false;
|
||||
}
|
||||
// We have not opted to use the new renderer so we should return true if we detect a class diagram
|
||||
return txt.match(/^\s*classDiagram/) !== null;
|
||||
return /^\s*classDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./classDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1373,9 +1373,54 @@ class Class2
|
||||
parser.parse(str);
|
||||
|
||||
const testNamespace = parser.yy.getNamespace('Namespace1');
|
||||
const testClasses = parser.yy.getClasses();
|
||||
expect(Object.keys(testNamespace.classes).length).toBe(2);
|
||||
expect(Object.keys(testNamespace.children).length).toBe(0);
|
||||
expect(testNamespace.classes['Class1'].id).toBe('Class1');
|
||||
expect(Object.keys(testClasses).length).toBe(2);
|
||||
});
|
||||
|
||||
it('should add relations between classes of different namespaces', function () {
|
||||
const str = `classDiagram
|
||||
A1 --> B1
|
||||
namespace A {
|
||||
class A1 {
|
||||
+foo : string
|
||||
}
|
||||
class A2 {
|
||||
+bar : int
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
class B1 {
|
||||
+foo : bool
|
||||
}
|
||||
class B2 {
|
||||
+bar : float
|
||||
}
|
||||
}
|
||||
A2 --> B2`;
|
||||
|
||||
parser.parse(str);
|
||||
const testNamespaceA = parser.yy.getNamespace('A');
|
||||
const testNamespaceB = parser.yy.getNamespace('B');
|
||||
const testClasses = parser.yy.getClasses();
|
||||
const testRelations = parser.yy.getRelations();
|
||||
expect(Object.keys(testNamespaceA.classes).length).toBe(2);
|
||||
expect(testNamespaceA.classes['A1'].members[0]).toBe('+foo : string');
|
||||
expect(testNamespaceA.classes['A2'].members[0]).toBe('+bar : int');
|
||||
expect(Object.keys(testNamespaceB.classes).length).toBe(2);
|
||||
expect(testNamespaceB.classes['B1'].members[0]).toBe('+foo : bool');
|
||||
expect(testNamespaceB.classes['B2'].members[0]).toBe('+bar : float');
|
||||
expect(Object.keys(testClasses).length).toBe(4);
|
||||
expect(testClasses['A1'].parent).toBe('A');
|
||||
expect(testClasses['A2'].parent).toBe('A');
|
||||
expect(testClasses['B1'].parent).toBe('B');
|
||||
expect(testClasses['B2'].parent).toBe('B');
|
||||
expect(testRelations[0].id1).toBe('A1');
|
||||
expect(testRelations[0].id2).toBe('B1');
|
||||
expect(testRelations[1].id1).toBe('A2');
|
||||
expect(testRelations[1].id2).toBe('B2');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-ignore d3 types are not available
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select, curveLinear } from 'd3';
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { log } from '../../logger.js';
|
||||
@@ -93,52 +93,51 @@ export const addClasses = function (
|
||||
log.info(classes);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
keys.forEach(function (id) {
|
||||
const vertex = classes[id];
|
||||
keys
|
||||
.filter((id) => classes[id].parent == parent)
|
||||
.forEach(function (id) {
|
||||
const vertex = classes[id];
|
||||
|
||||
/**
|
||||
* Variable for storing the classes for the vertex
|
||||
*/
|
||||
let cssClassStr = '';
|
||||
if (vertex.cssClasses.length > 0) {
|
||||
cssClassStr = cssClassStr + ' ' + vertex.cssClasses.join(' ');
|
||||
}
|
||||
/**
|
||||
* Variable for storing the classes for the vertex
|
||||
*/
|
||||
const cssClassStr = vertex.cssClasses.join(' ');
|
||||
|
||||
const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles);
|
||||
const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles);
|
||||
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
const vertexText = vertex.label ?? vertex.id;
|
||||
const radius = 0;
|
||||
const shape = 'class_box';
|
||||
// Use vertex id as text in the box if no text is provided by the graph definition
|
||||
const vertexText = vertex.label ?? vertex.id;
|
||||
const radius = 0;
|
||||
const shape = 'class_box';
|
||||
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: shape,
|
||||
labelText: sanitizeText(vertexText),
|
||||
classData: vertex,
|
||||
rx: radius,
|
||||
ry: radius,
|
||||
class: cssClassStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
domId: vertex.domId,
|
||||
tooltip: diagObj.db.getTooltip(vertex.id, parent) || '',
|
||||
haveCallback: vertex.haveCallback,
|
||||
link: vertex.link,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
type: vertex.type,
|
||||
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
|
||||
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
|
||||
};
|
||||
g.setNode(vertex.id, node);
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
shape: shape,
|
||||
labelText: sanitizeText(vertexText),
|
||||
classData: vertex,
|
||||
rx: radius,
|
||||
ry: radius,
|
||||
class: cssClassStr,
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
domId: vertex.domId,
|
||||
tooltip: diagObj.db.getTooltip(vertex.id, parent) || '',
|
||||
haveCallback: vertex.haveCallback,
|
||||
link: vertex.link,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
type: vertex.type,
|
||||
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
|
||||
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
|
||||
};
|
||||
g.setNode(vertex.id, node);
|
||||
|
||||
if (parent) {
|
||||
g.setParent(vertex.id, parent);
|
||||
}
|
||||
if (parent) {
|
||||
g.setParent(vertex.id, parent);
|
||||
}
|
||||
|
||||
log.info('setNode', node);
|
||||
});
|
||||
log.info('setNode', node);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -353,15 +352,11 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? // @ts-ignore Ignore type error for now
|
||||
|
||||
select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
// @ts-ignore Ignore type error for now
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
// @ts-ignore Ignore type error for now
|
||||
const element = root.select('#' + id + ' g');
|
||||
await render(
|
||||
element,
|
||||
@@ -377,7 +372,6 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf?.htmlLabels) {
|
||||
// @ts-ignore Ignore type error for now
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (const label of labels) {
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface ClassNode {
|
||||
members: string[];
|
||||
annotations: string[];
|
||||
domId: string;
|
||||
parent?: string;
|
||||
link?: string;
|
||||
linkTarget?: string;
|
||||
haveCallback?: boolean;
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'er';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*erDiagram/) !== null;
|
||||
return /^\s*erDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./erDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
// @ts-ignore: TODO: Fix ts errors
|
||||
import erParser from './parser/erDiagram.jison';
|
||||
import erDb from './erDb.js';
|
||||
import erRenderer from './erRenderer.js';
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import type { MermaidConfig } from '../../../config.type.js';
|
||||
import type { ExternalDiagramDefinition, DiagramDetector } from '../../../diagram-api/types.js';
|
||||
import type {
|
||||
ExternalDiagramDefinition,
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
} from '../../../diagram-api/types.js';
|
||||
|
||||
const id = 'flowchart-elk';
|
||||
|
||||
const detector: DiagramDetector = (txt: string, config?: MermaidConfig): boolean => {
|
||||
const detector: DiagramDetector = (txt, config): boolean => {
|
||||
if (
|
||||
// If diagram explicitly states flowchart-elk
|
||||
txt.match(/^\s*flowchart-elk/) ||
|
||||
/^\s*flowchart-elk/.test(txt) ||
|
||||
// If a flowchart/graph diagram has their default renderer set to elk
|
||||
(txt.match(/^\s*flowchart|graph/) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
(/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./flowchart-elk-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -208,21 +208,22 @@ export const updateLink = function (positions, style) {
|
||||
});
|
||||
};
|
||||
|
||||
export const addClass = function (id, style) {
|
||||
if (classes[id] === undefined) {
|
||||
classes[id] = { id: id, styles: [], textStyles: [] };
|
||||
}
|
||||
export const addClass = function (ids, style) {
|
||||
ids.split(',').forEach(function (id) {
|
||||
if (classes[id] === undefined) {
|
||||
classes[id] = { id, styles: [], textStyles: [] };
|
||||
}
|
||||
|
||||
if (style !== undefined && style !== null) {
|
||||
style.forEach(function (s) {
|
||||
if (s.match('color')) {
|
||||
const newStyle1 = s.replace('fill', 'bgFill');
|
||||
const newStyle2 = newStyle1.replace('color', 'fill');
|
||||
classes[id].textStyles.push(newStyle2);
|
||||
}
|
||||
classes[id].styles.push(s);
|
||||
});
|
||||
}
|
||||
if (style !== undefined && style !== null) {
|
||||
style.forEach(function (s) {
|
||||
if (s.match('color')) {
|
||||
const newStyle = s.replace('fill', 'bgFill').replace('color', 'fill');
|
||||
classes[id].textStyles.push(newStyle);
|
||||
}
|
||||
classes[id].styles.push(s);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,3 +41,26 @@ describe('flow db subgraphs', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('flow db addClass', () => {
|
||||
beforeEach(() => {
|
||||
flowDb.clear();
|
||||
});
|
||||
it('should detect many classes', () => {
|
||||
flowDb.addClass('a,b', ['stroke-width: 8px']);
|
||||
const classes = flowDb.getClasses();
|
||||
|
||||
expect(classes.hasOwnProperty('a')).toBe(true);
|
||||
expect(classes.hasOwnProperty('b')).toBe(true);
|
||||
expect(classes['a']['styles']).toEqual(['stroke-width: 8px']);
|
||||
expect(classes['b']['styles']).toEqual(['stroke-width: 8px']);
|
||||
});
|
||||
|
||||
it('should detect single class', () => {
|
||||
flowDb.addClass('a', ['stroke-width: 8px']);
|
||||
const classes = flowDb.getClasses();
|
||||
|
||||
expect(classes.hasOwnProperty('a')).toBe(true);
|
||||
expect(classes['a']['styles']).toEqual(['stroke-width: 8px']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DiagramDetector } from '../../diagram-api/types.js';
|
||||
import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'flowchart-v2';
|
||||
@@ -12,13 +12,13 @@ const detector: DiagramDetector = (txt, config) => {
|
||||
}
|
||||
|
||||
// If we have configured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
|
||||
if (txt.match(/^\s*graph/) !== null && config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
|
||||
if (/^\s*graph/.test(txt) && config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
|
||||
return true;
|
||||
}
|
||||
return txt.match(/^\s*flowchart/) !== null;
|
||||
return /^\s*flowchart/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./flowDiagram-v2.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'flowchart';
|
||||
|
||||
@@ -11,10 +15,10 @@ const detector: DiagramDetector = (txt, config) => {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return txt.match(/^\s*graph/) !== null;
|
||||
return /^\s*graph/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./flowDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -113,6 +113,22 @@ describe('[Style] when parsing', () => {
|
||||
expect(classes['exClass'].styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to declare multiple classes', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef firstClass,secondClass background:#bbb,border:1px solid red;'
|
||||
);
|
||||
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
|
||||
expect(classes['firstClass'].styles.length).toBe(2);
|
||||
expect(classes['firstClass'].styles[0]).toBe('background:#bbb');
|
||||
expect(classes['firstClass'].styles[1]).toBe('border:1px solid red');
|
||||
|
||||
expect(classes['secondClass'].styles.length).toBe(2);
|
||||
expect(classes['secondClass'].styles[0]).toBe('background:#bbb');
|
||||
expect(classes['secondClass'].styles[1]).toBe('border:1px solid red');
|
||||
});
|
||||
|
||||
it('should be possible to declare a class with a dot in the style', function () {
|
||||
const res = flow.parser.parse(
|
||||
'graph TD;classDef exClass background:#bbb,border:1.5px solid red;'
|
||||
@@ -322,4 +338,20 @@ describe('[Style] when parsing', () => {
|
||||
|
||||
expect(edges[0].type).toBe('arrow_point');
|
||||
});
|
||||
|
||||
it('should handle multiple vertices with style', function () {
|
||||
const res = flow.parser.parse(`
|
||||
graph TD
|
||||
classDef C1 stroke-dasharray:4
|
||||
classDef C2 stroke-dasharray:6
|
||||
A & B:::C1 & D:::C1 --> E:::C2
|
||||
`);
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
|
||||
expect(vert['A'].classes.length).toBe(0);
|
||||
expect(vert['B'].classes[0]).toBe('C1');
|
||||
expect(vert['D'].classes[0]).toBe('C1');
|
||||
expect(vert['E'].classes[0]).toBe('C2');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -359,7 +359,7 @@ statement
|
||||
|
||||
separator: NEWLINE | SEMI | EOF ;
|
||||
|
||||
|
||||
|
||||
verticeStatement: verticeStatement link node
|
||||
{ /* console.warn('vs',$1.stmt,$3); */ yy.addLink($1.stmt,$3,$2); $$ = { stmt: $3, nodes: $3.concat($1.nodes) } }
|
||||
| verticeStatement link node spaceList
|
||||
@@ -368,12 +368,16 @@ verticeStatement: verticeStatement link node
|
||||
|node { /*console.warn('noda', $1);*/ $$ = {stmt: $1, nodes:$1 }}
|
||||
;
|
||||
|
||||
node: vertex
|
||||
node: styledVertex
|
||||
{ /* console.warn('nod', $1); */ $$ = [$1];}
|
||||
| node spaceList AMP spaceList vertex
|
||||
| node spaceList AMP spaceList styledVertex
|
||||
{ $$ = $1.concat($5); /* console.warn('pip', $1[0], $5, $$); */ }
|
||||
;
|
||||
|
||||
styledVertex: vertex
|
||||
{ /* console.warn('nod', $1); */ $$ = $1;}
|
||||
| vertex STYLE_SEPARATOR idString
|
||||
{$$ = [$1];yy.setClass($1,$3)}
|
||||
{$$ = $1;yy.setClass($1,$3)}
|
||||
;
|
||||
|
||||
vertex: idString SQS text SQE
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'gantt';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*gantt/) !== null;
|
||||
return /^\s*gantt/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./ganttDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { DiagramDetector } from '../../diagram-api/types.js';
|
||||
import type { DiagramDetector, DiagramLoader } from '../../diagram-api/types.js';
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'gitGraph';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*gitGraph/) !== null;
|
||||
return /^\s*gitGraph/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./gitGraphDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { parser } from './parser/info.jison';
|
||||
import infoDb from './infoDb.js';
|
||||
describe('when parsing an info graph it', function () {
|
||||
let ex;
|
||||
beforeEach(function () {
|
||||
ex = parser;
|
||||
ex.yy = infoDb;
|
||||
});
|
||||
|
||||
it('should handle an info definition', function () {
|
||||
let str = `info
|
||||
showInfo`;
|
||||
|
||||
ex.parse(str);
|
||||
});
|
||||
});
|
||||
24
packages/mermaid/src/diagrams/info/info.spec.ts
Normal file
24
packages/mermaid/src/diagrams/info/info.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// @ts-ignore - jison doesn't export types
|
||||
import { parser } from './parser/info.jison';
|
||||
import { db } from './infoDb.js';
|
||||
|
||||
describe('info diagram', () => {
|
||||
beforeEach(() => {
|
||||
parser.yy = db;
|
||||
parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should handle an info definition', () => {
|
||||
const str = `info`;
|
||||
parser.parse(str);
|
||||
|
||||
expect(db.getInfo()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should handle an info definition with showInfo', () => {
|
||||
const str = `info showInfo`;
|
||||
parser.parse(str);
|
||||
|
||||
expect(db.getInfo()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
/** Created by knut on 15-01-14. */
|
||||
import { log } from '../../logger.js';
|
||||
import { clear } from '../../commonDb.js';
|
||||
|
||||
var message = '';
|
||||
var info = false;
|
||||
|
||||
export const setMessage = (txt) => {
|
||||
log.debug('Setting message to: ' + txt);
|
||||
message = txt;
|
||||
};
|
||||
|
||||
export const getMessage = () => {
|
||||
return message;
|
||||
};
|
||||
|
||||
export const setInfo = (inf) => {
|
||||
info = inf;
|
||||
};
|
||||
|
||||
export const getInfo = () => {
|
||||
return info;
|
||||
};
|
||||
|
||||
// export const parseError = (err, hash) => {
|
||||
// global.mermaidAPI.parseError(err, hash)
|
||||
// }
|
||||
|
||||
export default {
|
||||
setMessage,
|
||||
getMessage,
|
||||
setInfo,
|
||||
getInfo,
|
||||
clear,
|
||||
// parseError
|
||||
};
|
||||
23
packages/mermaid/src/diagrams/info/infoDb.ts
Normal file
23
packages/mermaid/src/diagrams/info/infoDb.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { InfoFields, InfoDB } from './infoTypes.js';
|
||||
|
||||
export const DEFAULT_INFO_DB: InfoFields = {
|
||||
info: false,
|
||||
} as const;
|
||||
|
||||
let info: boolean = DEFAULT_INFO_DB.info;
|
||||
|
||||
export const setInfo = (toggle: boolean): void => {
|
||||
info = toggle;
|
||||
};
|
||||
|
||||
export const getInfo = (): boolean => info;
|
||||
|
||||
const clear = (): void => {
|
||||
info = DEFAULT_INFO_DB.info;
|
||||
};
|
||||
|
||||
export const db: InfoDB = {
|
||||
clear,
|
||||
setInfo,
|
||||
getInfo,
|
||||
};
|
||||
@@ -1,20 +1,22 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'info';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*info/) !== null;
|
||||
return /^\s*info/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./infoDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
export const info: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
// @ts-ignore - jison doesn't export types
|
||||
import parser from './parser/info.jison';
|
||||
import db from './infoDb.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './infoRenderer.js';
|
||||
import { db } from './infoDb.js';
|
||||
import { renderer } from './infoRenderer.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles,
|
||||
};
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/** Created by knut on 14-12-11. */
|
||||
import { select } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
|
||||
/**
|
||||
* Draws a an info picture in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param {any} text
|
||||
* @param {any} id
|
||||
* @param {any} version
|
||||
*/
|
||||
export const draw = (text, id, version) => {
|
||||
try {
|
||||
// const parser = infoParser.parser;
|
||||
// parser.yy = db;
|
||||
log.debug('Rendering info diagram\n' + text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and Document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
|
||||
// Parse the graph definition
|
||||
// parser.parse(text);
|
||||
// log.debug('Parsed info diagram');
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
const g = svg.append('g');
|
||||
|
||||
g.append('text') // text label for the x axis
|
||||
.attr('x', 100)
|
||||
.attr('y', 40)
|
||||
.attr('class', 'version')
|
||||
.attr('font-size', '32px')
|
||||
.style('text-anchor', 'middle')
|
||||
.text('v ' + version);
|
||||
|
||||
svg.attr('height', 100);
|
||||
svg.attr('width', 400);
|
||||
// svg.attr('viewBox', '0 0 300 150');
|
||||
} catch (e) {
|
||||
log.error('Error while rendering info diagram');
|
||||
log.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
||||
50
packages/mermaid/src/diagrams/info/infoRenderer.ts
Normal file
50
packages/mermaid/src/diagrams/info/infoRenderer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { select } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
import type { DrawDefinition, HTML, SVG } from '../../diagram-api/types.js';
|
||||
|
||||
/**
|
||||
* Draws a an info picture 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.
|
||||
* @param version - MermaidJS version.
|
||||
*/
|
||||
const draw: DrawDefinition = (text, id, version) => {
|
||||
try {
|
||||
log.debug('rendering info diagram\n' + text);
|
||||
|
||||
const { securityLevel } = getConfig();
|
||||
// handle root and document for when rendering in sandbox mode
|
||||
let sandboxElement: HTML | undefined;
|
||||
let document: Document | null | undefined;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
document = sandboxElement.nodes()[0].contentDocument;
|
||||
}
|
||||
|
||||
// @ts-ignore - figure out how to assign HTML to document type
|
||||
const root: HTML =
|
||||
sandboxElement !== undefined && document !== undefined && document !== null
|
||||
? select(document)
|
||||
: select('body');
|
||||
|
||||
const svg: SVG = root.select('#' + id);
|
||||
svg.attr('height', 100);
|
||||
svg.attr('width', 400);
|
||||
|
||||
const g = svg.append('g');
|
||||
|
||||
g.append('text') // text label for the x axis
|
||||
.attr('x', 100)
|
||||
.attr('y', 40)
|
||||
.attr('class', 'version')
|
||||
.attr('font-size', '32px')
|
||||
.style('text-anchor', 'middle')
|
||||
.text('v ' + version);
|
||||
} catch (e) {
|
||||
log.error('error while rendering info diagram', e);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderer = { draw };
|
||||
11
packages/mermaid/src/diagrams/info/infoTypes.ts
Normal file
11
packages/mermaid/src/diagrams/info/infoTypes.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
|
||||
export interface InfoFields {
|
||||
info: boolean;
|
||||
}
|
||||
|
||||
export interface InfoDB extends DiagramDB {
|
||||
clear: () => void;
|
||||
setInfo: (info: boolean) => void;
|
||||
getInfo: () => boolean;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
const getStyles = () => ``;
|
||||
|
||||
export default getStyles;
|
||||
@@ -1,11 +1,15 @@
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
const id = 'mindmap';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*mindmap/) !== null;
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*mindmap/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./mindmap-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'pie';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*pie/) !== null;
|
||||
return /^\s*pie/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./pieDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'quadrantChart';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*quadrantChart/) !== null;
|
||||
return /^\s*quadrantChart/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./quadrantDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select } from 'd3';
|
||||
import * as configApi from '../../config.js';
|
||||
import { log } from '../../logger.js';
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'requirement';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*requirement(Diagram)?/) !== null;
|
||||
return /^\s*requirement(Diagram)?/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./requirementDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'sequence';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*sequenceDiagram/) !== null;
|
||||
return /^\s*sequenceDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./sequenceDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'stateDiagram';
|
||||
|
||||
const detector: DiagramDetector = (text, config) => {
|
||||
if (text.match(/^\s*stateDiagram-v2/) !== null) {
|
||||
const detector: DiagramDetector = (txt, config) => {
|
||||
if (/^\s*stateDiagram-v2/.test(txt)) {
|
||||
return true;
|
||||
}
|
||||
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') {
|
||||
return true;
|
||||
}
|
||||
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') {
|
||||
if (/^\s*stateDiagram/.test(txt) && config?.state?.defaultRenderer === 'dagre-wrapper') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./stateDiagram-v2.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'state';
|
||||
|
||||
@@ -8,10 +12,10 @@ const detector: DiagramDetector = (txt, config) => {
|
||||
if (config?.state?.defaultRenderer === 'dagre-wrapper') {
|
||||
return false;
|
||||
}
|
||||
return txt.match(/^\s*stateDiagram/) !== null;
|
||||
return /^\s*stateDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./stateDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -358,7 +358,7 @@ const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) =
|
||||
* Look through all of the documents (docs) in the parsedItems
|
||||
* Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction.
|
||||
* @param {object[]} parsedItem - the parsed statement item to look through
|
||||
* @param [defaultDir=DEFAULT_NESTED_DOC_DIR] - the direction to use if none is found
|
||||
* @param [defaultDir] - the direction to use if none is found
|
||||
* @returns {string}
|
||||
*/
|
||||
const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'timeline';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*timeline/) !== null;
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*timeline/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./timeline-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @ts-ignore - db not typed yet
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select, Selection } from 'd3';
|
||||
import svgDraw from './svgDraw.js';
|
||||
import { log } from '../../logger.js';
|
||||
@@ -46,11 +46,9 @@ export const draw = function (text: string, id: string, version: string, diagObj
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? // @ts-ignore d3 types are wrong
|
||||
select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
|
||||
// @ts-ignore d3 types are wrong
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
svg.append('g');
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'journey';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*journey/) !== null;
|
||||
return /^\s*journey/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./journeyDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
@@ -20,6 +20,10 @@ The definitions that can be generated the Live-Editor are also backwards-compati
|
||||
|
||||
[Eddie Jaoude: Can you code your diagrams?](https://www.youtube.com/watch?v=9HZzKkAqrX8)
|
||||
|
||||
## Mermaid with OpenAI
|
||||
|
||||
[Elle Neal: Mind Mapping with AI: An Accessible Approach for Neurodiverse Learners Tutorial:](https://medium.com/@elle.neal_71064/mind-mapping-with-ai-an-accessible-approach-for-neurodiverse-learners-1a74767359ff), [Demo:](https://databutton.com/v/jk9vrghc)
|
||||
|
||||
## Mermaid with HTML
|
||||
|
||||
Examples are provided in [Getting Started](../intro/n00b-gettingStarted.md)
|
||||
|
||||
@@ -60,7 +60,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
|
||||
## Blogs
|
||||
|
||||
- [Wordpress](https://wordpress.org)
|
||||
- [WordPress](https://wordpress.org)
|
||||
- [WordPress Markdown Editor](https://wordpress.org/plugins/wp-githuber-md)
|
||||
- [WP-ReliableMD](https://wordpress.org/plugins/wp-reliablemd/)
|
||||
- [Hexo](https://hexo.io)
|
||||
@@ -78,7 +78,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Plugin for Mermaid.js](https://github.com/eFrane/vuepress-plugin-mermaidjs)
|
||||
- [Grav CMS](https://getgrav.org/)
|
||||
- [Mermaid Diagrams](https://github.com/DanielFlaum/grav-plugin-mermaid-diagrams)
|
||||
- [Gitlab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
|
||||
- [GitLab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
|
||||
|
||||
## Communication
|
||||
|
||||
@@ -98,7 +98,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
|
||||
- [Semantic Media Wiki](https://semantic-mediawiki.org)
|
||||
- [Mermaid Plugin](https://github.com/SemanticMediaWiki/Mermaid)
|
||||
- [FosWiki](https://foswiki.org)
|
||||
- [Foswiki](https://foswiki.org)
|
||||
- [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin)
|
||||
- [DokuWiki](https://dokuwiki.org)
|
||||
- [Mermaid Plugin](https://www.dokuwiki.org/plugin:mermaid)
|
||||
@@ -155,6 +155,8 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
|
||||
- [CKEditor](https://github.com/ckeditor/ckeditor5)
|
||||
- [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
|
||||
- [Standard Notes](https://standardnotes.com/)
|
||||
- [sn-mermaid](https://github.com/nienow/sn-mermaid)
|
||||
|
||||
## Document Generation
|
||||
|
||||
@@ -166,7 +168,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [rehype-mermaidjs](https://github.com/remcohaszing/rehype-mermaidjs)
|
||||
- [Gatsby](https://www.gatsbyjs.com/)
|
||||
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
|
||||
- [jSDoc](https://jsdoc.app/)
|
||||
- [JSDoc](https://jsdoc.app/)
|
||||
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
|
||||
- [MkDocs](https://www.mkdocs.org)
|
||||
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.1.16",
|
||||
"@unocss/reset": "^0.52.0",
|
||||
"@vite-pwa/vitepress": "^0.0.5",
|
||||
"@unocss/reset": "^0.53.0",
|
||||
"@vite-pwa/vitepress": "^0.2.0",
|
||||
"@vitejs/plugin-vue": "^4.2.1",
|
||||
"fast-glob": "^3.2.12",
|
||||
"https-localhost": "^4.7.1",
|
||||
"pathe": "^1.1.0",
|
||||
"unocss": "^0.52.0",
|
||||
"unplugin-vue-components": "^0.24.1",
|
||||
"unocss": "^0.53.0",
|
||||
"unplugin-vue-components": "^0.25.0",
|
||||
"vite": "^4.3.3",
|
||||
"vite-plugin-pwa": "^0.15.0",
|
||||
"vitepress": "1.0.0-beta.1",
|
||||
"workbox-window": "^6.5.4"
|
||||
"vite-plugin-pwa": "^0.16.0",
|
||||
"vitepress": "1.0.0-beta.3",
|
||||
"workbox-window": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,6 +605,12 @@ In the example below the style defined in the linkStyle statement will belong to
|
||||
linkStyle 3 stroke:#ff3,stroke-width:4px,color:red;
|
||||
```
|
||||
|
||||
It is also possible to add style to multiple links in a single statement, by separating link numbers with commas:
|
||||
|
||||
```
|
||||
linkStyle 1,2,7 color:blue;
|
||||
```
|
||||
|
||||
### Styling line curves
|
||||
|
||||
It is possible to style the type of curve used for lines between items, if the default method does not meet your needs.
|
||||
@@ -638,12 +644,18 @@ flowchart LR
|
||||
More convenient than defining the style every time is to define a class of styles and attach this class to the nodes that
|
||||
should have a different look.
|
||||
|
||||
a class definition looks like the example below:
|
||||
A class definition looks like the example below:
|
||||
|
||||
```
|
||||
classDef className fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
```
|
||||
|
||||
Also, it is possible to define style to multiple classes in one statement:
|
||||
|
||||
```
|
||||
classDef firstClassName,secondClassName font-size:12pt;
|
||||
```
|
||||
|
||||
Attachment of a class to a node is done as per below:
|
||||
|
||||
```
|
||||
|
||||
@@ -19,13 +19,13 @@ Mermaid can render Gantt diagrams as SVG, PNG or a MarkDown link that can be pas
|
||||
```mermaid-example
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
dateFormat YYYY-MM-DD
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1, 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
Task in Another :2014-01-12, 12d
|
||||
another task :24d
|
||||
```
|
||||
|
||||
## Syntax
|
||||
@@ -66,10 +66,10 @@ gantt
|
||||
It is possible to set multiple dependencies separated by space:
|
||||
|
||||
```mermaid-example
|
||||
gantt
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
gantt
|
||||
apple :a, 2017-07-20, 1w
|
||||
banana :crit, b, 2017-07-23, 1d
|
||||
cherry :active, c, after b a, 1d
|
||||
```
|
||||
|
||||
### Title
|
||||
@@ -88,12 +88,12 @@ You can add milestones to the diagrams. Milestones differ from tasks as they rep
|
||||
|
||||
```mermaid-example
|
||||
gantt
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
Initial milestone : milestone, m1, 17:49,2min
|
||||
taska2 : 10min
|
||||
taska3 : 5min
|
||||
Final milestone : milestone, m2, 18:14, 2min
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
Initial milestone : milestone, m1, 17:49, 2m
|
||||
Task A : 10m
|
||||
Task B : 5m
|
||||
Final milestone : milestone, m2, 18:08, 4m
|
||||
```
|
||||
|
||||
## Setting dates
|
||||
@@ -214,15 +214,14 @@ Comments can be entered within a gantt chart, which will be ignored by the parse
|
||||
```mermaid
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
%% this is a comment
|
||||
dateFormat YYYY-MM-DD
|
||||
%% This is a comment
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1, 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
|
||||
Task in Another :2014-01-12, 12d
|
||||
another task :24d
|
||||
```
|
||||
|
||||
## Styling
|
||||
@@ -350,7 +349,7 @@ Beginner's tip—a full example using interactive links in an html context:
|
||||
dateFormat YYYY-MM-DD
|
||||
|
||||
section Clickable
|
||||
Visit mermaidjs :active, cl1, 2014-01-07, 3d
|
||||
Visit mermaidjs :active, cl1, 2014-01-07, 3d
|
||||
Print arguments :cl2, after cl1, 3d
|
||||
Print task :cl3, after cl2, 3d
|
||||
|
||||
|
||||
@@ -133,6 +133,6 @@ quadrantChart
|
||||
y-axis Not Important --> "Important ❤"
|
||||
quadrant-1 Plan
|
||||
quadrant-2 Do
|
||||
quadrant-3 Deligate
|
||||
quadrant-3 Delegate
|
||||
quadrant-4 Delete
|
||||
```
|
||||
|
||||
@@ -172,9 +172,11 @@ let us look at same example, where we have disabled the multiColor option.
|
||||
|
||||
### Customizing Color scheme
|
||||
|
||||
You can customize the color scheme using the `cScale0` to `cScale11` theme variables. Mermaid allows you to set unique colors for up-to 12 sections, where `cScale0` variable will drive the value of the first section or time-period, `cScale1` will drive the value of the second section and so on.
|
||||
You can customize the color scheme using the `cScale0` to `cScale11` theme variables, which will change the background colors. Mermaid allows you to set unique colors for up-to 12 sections, where `cScale0` variable will drive the value of the first section or time-period, `cScale1` will drive the value of the second section and so on.
|
||||
In case you have more than 12 sections, the color scheme will start to repeat.
|
||||
|
||||
If you also want to change the foreground color of a section, you can do so use theme variables corresponding `cScaleLabel0` to `cScaleLabel11` variables.
|
||||
|
||||
NOTE: Default values for these theme variables are picked from the selected theme. If you want to override the default values, you can use the `initialize` call to add your custom theme variable values.
|
||||
|
||||
Example:
|
||||
@@ -183,9 +185,9 @@ Now let's override the default values for the `cScale0` to `cScale2` variables:
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
|
||||
'cScale0': '#ff0000',
|
||||
'cScale0': '#ff0000', 'cScaleLabel0': '#ffffff',
|
||||
'cScale1': '#00ff00',
|
||||
'cScale2': '#0000ff'
|
||||
'cScale2': '#0000ff', 'cScaleLabel2': '#ffffff'
|
||||
} } }%%
|
||||
timeline
|
||||
title History of Social Media Platform
|
||||
|
||||
@@ -78,7 +78,6 @@ export interface ParseOptions {
|
||||
}
|
||||
|
||||
// This makes it clear that we're working with a d3 selected element of some kind, even though it's hard to specify the exact type.
|
||||
// @ts-ignore Could replicate the type definition in d3. This also makes it possible to use the untyped info from the js diagram files.
|
||||
export type D3Element = any;
|
||||
|
||||
export interface RenderResult {
|
||||
@@ -491,13 +490,7 @@ const render = async function (
|
||||
? diag.renderer.getClasses(text, diag)
|
||||
: {};
|
||||
|
||||
const rules = createUserStyles(
|
||||
config,
|
||||
graphType,
|
||||
// @ts-ignore convert renderer to TS.
|
||||
diagramClassDefs,
|
||||
idSelector
|
||||
);
|
||||
const rules = createUserStyles(config, graphType, diagramClassDefs, idSelector);
|
||||
|
||||
const style1 = document.createElement('style');
|
||||
style1.innerHTML = rules;
|
||||
|
||||
@@ -22,7 +22,6 @@ import er from './diagrams/er/styles.js';
|
||||
import error from './diagrams/error/styles.js';
|
||||
import git from './diagrams/git/styles.js';
|
||||
import gantt from './diagrams/gantt/styles.js';
|
||||
import info from './diagrams/info/styles.js';
|
||||
import pie from './diagrams/pie/styles.js';
|
||||
import requirement from './diagrams/requirement/styles.js';
|
||||
import sequence from './diagrams/sequence/styles.js';
|
||||
@@ -92,7 +91,6 @@ describe('styles', () => {
|
||||
flowchartElk,
|
||||
gantt,
|
||||
git,
|
||||
info,
|
||||
journey,
|
||||
mindmap,
|
||||
pie,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { FlowChartStyleOptions } from './diagrams/flowchart/styles.js';
|
||||
import { log } from './logger.js';
|
||||
import type { DiagramStylesProvider } from './diagram-api/types.js';
|
||||
|
||||
const themes: Record<string, any> = {};
|
||||
const themes: Record<string, DiagramStylesProvider> = {};
|
||||
|
||||
const getStyles = (
|
||||
type: string,
|
||||
@@ -73,8 +74,10 @@ const getStyles = (
|
||||
`;
|
||||
};
|
||||
|
||||
export const addStylesForDiagram = (type: string, diagramTheme: unknown): void => {
|
||||
themes[type] = diagramTheme;
|
||||
export const addStylesForDiagram = (type: string, diagramTheme?: DiagramStylesProvider): void => {
|
||||
if (diagramTheme !== undefined) {
|
||||
themes[type] = diagramTheme;
|
||||
}
|
||||
};
|
||||
|
||||
export default getStyles;
|
||||
|
||||
Reference in New Issue
Block a user