From e3c426de8662dc0677da0e3f8c78563a4e1e582e Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Tue, 27 Aug 2024 08:37:39 -0700 Subject: [PATCH 001/155] Initial work on updating to new renderer --- cypress/platform/yari.html | 32 ++++ .../mermaid/src/diagrams/class/classDb.ts | 8 + .../src/diagrams/class/classDiagram-v2.ts | 2 +- .../class/classRenderer-v3-unified.ts | 87 +++++++++++ .../mermaid/src/diagrams/class/classTypes.ts | 18 +++ .../rendering-elements/nodes.js | 2 + .../rendering-elements/shapes/classBox.ts | 139 ++++++++++++++++++ 7 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 cypress/platform/yari.html create mode 100644 packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts create mode 100644 packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts diff --git a/cypress/platform/yari.html b/cypress/platform/yari.html new file mode 100644 index 0000000000..5031a1ed2d --- /dev/null +++ b/cypress/platform/yari.html @@ -0,0 +1,32 @@ + + +
+      classDiagram
+      class Square~Shape~{
+        int id
+        List~int~ position
+        setPoints(List~int~ points)
+        getPoints() List~int~
+      }
+
+Square : -List~string~ messages
+Square : +setMessages(List~string~ messages)
+Square : +getMessages() List~string~
+Square : +getDistanceMatrix() List~List~int~~
+    
+ +
classDiagram class Duck{ +String beakColor +swim() +quack() }
+ + + + diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index 1fec5c2dc4..06046f8823 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -80,6 +80,8 @@ export const addClass = function (_id: string) { id: name, type: type, label: name, + text: `${name}${type ? `<${type}>` : ''}`, + shape: 'classBox', cssClasses: [], methods: [], members: [], @@ -472,6 +474,11 @@ export const setCssStyle = function (id: string, styles: string[]) { } }; +export const getData = () => { + const config = getConfig(); + return { nodes: classes, edges: relations, other: {}, config, direction: getDirection() }; +}; + export default { setAccTitle, getAccTitle, @@ -509,4 +516,5 @@ export default { getNamespace, getNamespaces, setCssStyle, + getData, }; diff --git a/packages/mermaid/src/diagrams/class/classDiagram-v2.ts b/packages/mermaid/src/diagrams/class/classDiagram-v2.ts index ec5398d29d..6a3747e418 100644 --- a/packages/mermaid/src/diagrams/class/classDiagram-v2.ts +++ b/packages/mermaid/src/diagrams/class/classDiagram-v2.ts @@ -3,7 +3,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js'; import parser from './parser/classDiagram.jison'; import db from './classDb.js'; import styles from './styles.js'; -import renderer from './classRenderer-v2.js'; +import renderer from './classRenderer-v3-unified.js'; export const diagram: DiagramDefinition = { parser, diff --git a/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts new file mode 100644 index 0000000000..404a53c6c9 --- /dev/null +++ b/packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts @@ -0,0 +1,87 @@ +import { getConfig } from '../../diagram-api/diagramAPI.js'; +import type { DiagramStyleClassDef } from '../../diagram-api/types.js'; +import { log } from '../../logger.js'; +import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js'; +import { render } from '../../rendering-util/render.js'; +import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js'; +import type { LayoutData } from '../../rendering-util/types.js'; +import utils from '../../utils.js'; +// import { CSS_DIAGRAM, DEFAULT_NESTED_DOC_DIR } from './stateCommon.js'; + +/** + * Get the direction from the statement items. + * 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 parsedItem - the parsed statement item to look through + * @param defaultDir - the direction to use if none is found + * @returns The direction to use + */ +export const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => { + if (!parsedItem.doc) { + return defaultDir; + } + + let dir = defaultDir; + + for (const parsedItemDoc of parsedItem.doc) { + if (parsedItemDoc.stmt === 'dir') { + dir = parsedItemDoc.value; + } + } + + return dir; +}; + +export const getClasses = function ( + text: string, + diagramObj: any +): Map { + // diagramObj.db.extract(diagramObj.db.getRootDocV2()); + return diagramObj.db.getClasses(); +}; + +export const draw = async function (text: string, id: string, _version: string, diag: any) { + log.info('REF0:'); + log.info('Drawing class diagram (v3)', id); + const { securityLevel, state: conf, layout } = getConfig(); + // Extracting the data from the parsed structure into a more usable form + // Not related to the refactoring, but this is the first step in the rendering process + // diag.db.extract(diag.db.getRootDocV2()); + + //const DIR = getDir(diag.db.getRootDocV2()); + + // The getData method provided in all supported diagrams is used to extract the data from the parsed structure + // into the Layout data format + const data4Layout = diag.db.getData() as LayoutData; + + // Create the root SVG - the element is the div containing the SVG element + const { element, svg } = getDiagramElements(id, securityLevel); + + data4Layout.type = diag.type; + data4Layout.layoutAlgorithm = layout; + + // TODO: Should we move these two to baseConfig? These types are not there in StateConfig. + + data4Layout.nodeSpacing = conf?.nodeSpacing || 50; + data4Layout.rankSpacing = conf?.rankSpacing || 50; + data4Layout.markers = ['barb']; + data4Layout.diagramId = id; + await render(data4Layout, svg, element); + const padding = 8; + utils.insertTitle( + element, + 'statediagramTitleText', + conf?.titleTopMargin ?? 25, + diag.db.getDiagramTitle() + ); + + const CSS_DIAGRAM = 'classDiagram'; + + setupViewPortForSVG(svg, padding, CSS_DIAGRAM, conf?.useMaxWidth ?? true); +}; + +export default { + getClasses, + draw, + getDir, +}; diff --git a/packages/mermaid/src/diagrams/class/classTypes.ts b/packages/mermaid/src/diagrams/class/classTypes.ts index f1955a2246..cb3ba83257 100644 --- a/packages/mermaid/src/diagrams/class/classTypes.ts +++ b/packages/mermaid/src/diagrams/class/classTypes.ts @@ -5,6 +5,7 @@ export interface ClassNode { id: string; type: string; label: string; + text: string; cssClasses: string[]; methods: ClassMember[]; members: ClassMember[]; @@ -30,6 +31,7 @@ export class ClassMember { cssStyle!: string; memberType!: 'method' | 'attribute'; visibility!: Visibility; + text: string; /** * denote if static or to determine which css class to apply to the node * @defaultValue '' @@ -50,6 +52,7 @@ export class ClassMember { this.memberType = memberType; this.visibility = ''; this.classifier = ''; + this.text = ''; const sanitizedInput = sanitizeText(input, getConfig()); this.parseMember(sanitizedInput); } @@ -118,6 +121,21 @@ export class ClassMember { } this.classifier = potentialClassifier; + this.text = `${this.visibility}${this.id}${this.memberType === 'method' ? `(${this.parameters})${this.returnType ? ' : ' + this.returnType : ''}` : ''}`; //.replaceAll('~', '<'); + const combinedText = `${this.visibility}${this.id}${this.memberType === 'method' ? `(${this.parameters})${this.returnType ? ' : ' + this.returnType : ''}` : ''}`; + if (combinedText.includes('~')) { + let count = (combinedText.match(/~/g) ?? []).length; + + // Replace all '~' with '>' + let replacedRaw = combinedText.replaceAll('~', '>'); + + // Replace the first half of '>' with '<' + while (count > 0) { + replacedRaw = replacedRaw.replace('>', '<'); + count -= 2; // Each iteration replaces one '>' with '<', so reduce count by 2 + } + this.text = replacedRaw; + } } parseClassifier() { diff --git a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js index 2f69a36bcd..5b6ce08d5c 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/nodes.js +++ b/packages/mermaid/src/rendering-util/rendering-elements/nodes.js @@ -22,6 +22,7 @@ import { lean_left } from './shapes/leanLeft.js'; import { trapezoid } from './shapes/trapezoid.js'; import { inv_trapezoid } from './shapes/invertedTrapezoid.js'; import { labelRect } from './shapes/labelRect.js'; +import { classBox } from './shapes/classBox.js'; const shapes = { state, @@ -47,6 +48,7 @@ const shapes = { trapezoid, inv_trapezoid, labelRect, + classBox, }; const nodeElems = new Map(); diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts new file mode 100644 index 0000000000..86fb40a627 --- /dev/null +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts @@ -0,0 +1,139 @@ +import { getNodeClasses } from './util.js'; +import { getConfig } from '$root/diagram-api/diagramAPI.js'; +import { createText } from '../../createText.js'; +import { select } from 'd3'; +import type { Node } from '$root/rendering-util/types.d.ts'; +import { evaluate } from '$root/diagrams/common/common.js'; +import { calculateTextDimensions, calculateTextWidth } from '$root/utils.js'; +import { styles2String } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; + +export const classBox = async (parent: SVGAElement, node: Node): Promise => { + const { labelStyles, nodeStyles } = styles2String(node); + node.labelStyle = labelStyles; + + const mainGroup = parent + .insert('g') + .attr('class', getNodeClasses(node)) + .attr('style', nodeStyles) + .attr('id', node.domId || node.id); + let labelGroup = null; + let membersGroup = null; + let methodsGroup = null; + + let labelGroupHeight = 0; + let membersGroupHeight = 0; + + const config = getConfig(); + + const PADDING = config.class.padding; + const GAP = PADDING; + + if (node.label) { + labelGroup = mainGroup.insert('g').attr('class', 'label-group'); + // TODO: Add Padding + await helper(labelGroup, node, 0); + const labelGroupBBox = labelGroup.node().getBBox(); + labelGroupHeight = labelGroupBBox.height; + } + + if (node.members) { + membersGroup = mainGroup.insert('g').attr('class', 'members-group'); + let yOffset = 0; + for (const member of node.members) { + await helper(membersGroup, member, yOffset); + yOffset += calculateTextDimensions(member.text, config).height; + } + membersGroupHeight = membersGroup.node().getBBox().height; + membersGroup.attr('transform', `translate(0, ${labelGroupHeight + GAP * 3})`); + } + + if (node.methods) { + methodsGroup = mainGroup.insert('g').attr('class', 'methods-group'); + let methodsYOffset = 0; + for (const method of node.methods) { + await helper(methodsGroup, method, methodsYOffset); + methodsYOffset += calculateTextDimensions(method.text, config).height; + } + // TODO: Update transform + methodsGroup.attr( + 'transform', + `translate(0, ${labelGroupHeight + (membersGroupHeight ? membersGroupHeight + GAP * 5 : GAP * 3)})` + ); + } + + const mainGroupBBox = mainGroup.node().getBBox(); + const labelGroupBBox = labelGroup.node().getBBox(); + // Center label + labelGroup.attr( + 'transform', + `translate(${mainGroupBBox.width / 2 - labelGroupBBox.width / 2}, 0)` + ); + + // Insert the rectangle around the main group + mainGroup + .insert('rect', ':first-child') + .attr('class', 'basic label-container') + .attr('style', nodeStyles) + .attr('data-id', 'abc') + .attr('data-et', 'node') + .attr('x', mainGroupBBox.x - PADDING) + .attr('y', mainGroupBBox.y - PADDING) + .attr('width', mainGroupBBox.width + 2 * PADDING) + .attr('height', mainGroupBBox.height + 2 * PADDING); + + // Render separating lines. + if (node.label) { + mainGroup + .insert('line') + .attr('x1', 0 - PADDING) + .attr('y1', labelGroupHeight - GAP) + .attr('x2', mainGroupBBox.width + PADDING) + .attr('y2', labelGroupHeight - GAP) + .attr('class', 'divider'); + } + + if (node.members.length > 0 && node.methods.length > 0) { + mainGroup + .insert('line') + .attr('x1', 0 - PADDING) + .attr('y1', labelGroupHeight + membersGroupHeight + GAP * 2) + .attr('x2', mainGroupBBox.width + PADDING) + .attr('y2', labelGroupHeight + membersGroupHeight + GAP * 2) + .attr('class', 'divider'); + } + + return mainGroup; +}; + +const helper = async (parentGroup, node, yOffset) => { + const textEl = parentGroup.insert('g').attr('class', 'label').attr('style', node.labelStyle); + const textContent = node.text; + const config = getConfig(); + const text = await createText( + textEl, + textContent, + { + width: calculateTextWidth(textContent, config), + classes: 'markdown-node-label', + style: node.labelStyle, + useHtmlLabels: true, + }, + config + ); + + let bbox = text.getBBox(); + + if (evaluate(config.flowchart.htmlLabels)) { + const div = text.children[0]; + const dv = select(text); + + bbox = div.getBoundingClientRect(); + dv.attr('width', bbox.width); + dv.attr('height', bbox.height); + } + + textEl.attr('transform', 'translate(' + 0 + ', ' + (-bbox.height / 2 + yOffset) + ')'); + if (node.centerLabel) { + textEl.attr('transform', 'translate(' + -bbox.width / 2 + ', ' + -bbox.height / 2 + ')'); + } +}; From 27f7b615cc7faddc289b5abab204e48736524711 Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 10:50:13 -0700 Subject: [PATCH 002/155] Add more tests / samples --- cypress/platform/yari.html | 308 +++++++++++++++++++++++++++++++++++-- 1 file changed, 292 insertions(+), 16 deletions(-) diff --git a/cypress/platform/yari.html b/cypress/platform/yari.html index 5031a1ed2d..4459aeb374 100644 --- a/cypress/platform/yari.html +++ b/cypress/platform/yari.html @@ -1,21 +1,261 @@ -
-      classDiagram
-      class Square~Shape~{
-        int id
-        List~int~ position
-        setPoints(List~int~ points)
-        getPoints() List~int~
-      }
-
-Square : -List~string~ messages
-Square : +setMessages(List~string~ messages)
-Square : +getMessages() List~string~
-Square : +getDistanceMatrix() List~List~int~~
-    
- -
classDiagram class Duck{ +String beakColor +swim() +quack() }
+

Class Nodes

+
+
+

Basic Class

+
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Complex Class

+
+                classDiagram
+                class Square~Shape~{
+                  int id
+                  List~int~ position
+                  setPoints(List~int~ points)
+                  getPoints() List~int~
+                }
+          
+          Square : -List~string~ messages
+          Square : +setMessages(List~string~ messages)
+          Square : +getMessages() List~string~
+          Square : +getDistanceMatrix() List~List~int~~
+              
+
+
+

No Attributes

+
+          classDiagram
+          class Duck {
+            +swim()
+            +quack()
+          }
+        
+
+
+

No Methods

+
+          classDiagram
+          class Duck {
+            +String beakColor
+          }
+        
+
+
+

Only Class Name

+

Empty line as attribute

+
+          classDiagram
+          class Duck {
+            
+          }
+        
+
+
+

Visibility and Types

+

(Further tilde testing)

+
+ classDiagram class Duck{ ~interface~~~ +String beakColor #swim() ~quack()~~~ + -test()~~~~~~~ +deposit(amount) bool } +
+
+
+

Label

+
+          classDiagram
+          class Animal~test~["Animal with a label"]
+        
+
+
+

Link

+
+          classDiagram
+          class Shape
+          link Shape "https://www.github.com" "This is a tooltip for a link"
+        
+
+
+

Click

+
+          classDiagram
+          class Shape
+          click Shape href "https://www.github.com" "This is a tooltip for a link"
+        
+
+
+

Neutral Theme

+
+          ---
+          config:
+            theme: neutral
+          ---
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Dark Theme

+
+          ---
+          config:
+            theme: dark
+          ---
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Forest Theme

+
+          ---
+          config:
+            theme: forest
+          ---
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Base Theme

+
+          ---
+          config:
+            theme: base
+          ---
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Custom Theme

+
+          %%{
+            init: {
+              'theme': 'base',
+              'themeVariables': {
+                'primaryColor': '#BB2528',
+                'primaryTextColor': '#fff',
+                'primaryBorderColor': '#7C0000',
+                'lineColor': '#F8B229',
+                'secondaryColor': '#006100',
+                'tertiaryColor': '#fff'
+              }
+            }
+          }%%
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+        
+
+
+

Styling within Diagram

+
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+          style Duck fill:#f9f,stroke:#333,stroke-width:8px
+        
+
+
+

Styling with Class

+
+          classDiagram
+          class Duck {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+          class Duck:::styleClass
+        
+
+
+

Diagram Testing

+
+
+

Class Nodes Only

+
+          ---
+          title: Animal example
+          ---
+          classDiagram
+              Animal : +int age
+              Animal : +String gender
+              Animal: +isMammal()
+              Animal: +mate()
+              class Duck{
+                  +String beakColor
+                  +swim()
+                  +quack()
+              }
+              class Fish{
+                  -int sizeInFeet
+                  -canEat()
+              }
+              class Zebra{
+                  +bool is_wild
+                  +run()
+              }
+        
+
+
+

Class Nodes LR

+
+          ---
+          title: Animal example
+          ---
+          classDiagram
+              direction LR
+              Animal : +int age
+              Animal : +String gender
+              Animal: +isMammal()
+              Animal: +mate()
+              class Duck{
+                  +String beakColor
+                  +swim()
+                  +quack()
+              }
+              class Fish{
+                  -int sizeInFeet
+                  -canEat()
+              }
+              class Zebra{
+                  +bool is_wild
+                  +run()
+              }
+        
+
+
+ From 8745daa701d1e0a154bb90d657224389a843914e Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 10:53:15 -0700 Subject: [PATCH 003/155] Add handling for escape type --- packages/mermaid/src/rendering-util/handle-markdown-text.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mermaid/src/rendering-util/handle-markdown-text.ts b/packages/mermaid/src/rendering-util/handle-markdown-text.ts index 4b6a04428d..1bff5a9776 100644 --- a/packages/mermaid/src/rendering-util/handle-markdown-text.ts +++ b/packages/mermaid/src/rendering-util/handle-markdown-text.ts @@ -85,6 +85,8 @@ export function markdownToHTML(markdown: string, { markdownAutoWrap }: MermaidCo return ''; } else if (node.type === 'html') { return `${node.text}`; + } else if (node.type === 'escape') { + return node.text; } return `Unsupported markdown: ${node.type}`; } From 191e4217fc3f968777cc17e734d494b4c56273ff Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 10:54:09 -0700 Subject: [PATCH 004/155] Adjust classNode text when label is set --- packages/mermaid/src/diagrams/class/classDb.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mermaid/src/diagrams/class/classDb.ts b/packages/mermaid/src/diagrams/class/classDb.ts index 06046f8823..32d0076345 100644 --- a/packages/mermaid/src/diagrams/class/classDb.ts +++ b/packages/mermaid/src/diagrams/class/classDb.ts @@ -58,6 +58,8 @@ export const setClassLabel = function (_id: string, label: string) { const { className } = splitClassNameAndType(id); classes.get(className)!.label = label; + classes.get(className)!.text = + `${label}${classes.get(className)!.type ? `<${classes.get(className)!.type}>` : ''}`; }; /** From 20a58d6dbb1ba7b1296538717105d2bf80fc692b Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 10:56:14 -0700 Subject: [PATCH 005/155] Add special handling to avoid markdown to HTML issues --- .../mermaid/src/diagrams/class/classTypes.ts | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/mermaid/src/diagrams/class/classTypes.ts b/packages/mermaid/src/diagrams/class/classTypes.ts index cb3ba83257..4ac125fad7 100644 --- a/packages/mermaid/src/diagrams/class/classTypes.ts +++ b/packages/mermaid/src/diagrams/class/classTypes.ts @@ -121,20 +121,45 @@ export class ClassMember { } this.classifier = potentialClassifier; - this.text = `${this.visibility}${this.id}${this.memberType === 'method' ? `(${this.parameters})${this.returnType ? ' : ' + this.returnType : ''}` : ''}`; //.replaceAll('~', '<'); + this.text = `${this.visibility}${this.id}${this.memberType === 'method' ? `(${this.parameters})${this.returnType ? ' : ' + this.returnType : ''}` : ''}`; const combinedText = `${this.visibility}${this.id}${this.memberType === 'method' ? `(${this.parameters})${this.returnType ? ' : ' + this.returnType : ''}` : ''}`; if (combinedText.includes('~')) { - let count = (combinedText.match(/~/g) ?? []).length; - - // Replace all '~' with '>' - let replacedRaw = combinedText.replaceAll('~', '>'); - - // Replace the first half of '>' with '<' - while (count > 0) { - replacedRaw = replacedRaw.replace('>', '<'); - count -= 2; // Each iteration replaces one '>' with '<', so reduce count by 2 + const numOfTildes = (combinedText.substring(1).match(/~/g) ?? []).length; + let count = numOfTildes; + if (count !== 1) { + const odd = count % 2 > 0; + + // Replace all '~' with '>' + let replacedRaw = combinedText.substring(1).replaceAll('~', '>'); + + // Replace the first half of '>' with '<' + while (count > 0) { + replacedRaw = replacedRaw.replace('>', '<'); + count -= 2; // Each iteration replaces one '>' with '<', so reduce count by 2 + } + if (odd) { + if (this.memberType === 'method') { + replacedRaw = replacedRaw.replace('<', '~'); + } else { + // Replace the middle occurrence of '<' with '~' + const ltOccurrences = replacedRaw.match(/</g) ?? []; + if (ltOccurrences.length > 1) { + let ltCount = 0; + + replacedRaw = replacedRaw.replace(/</g, (match) => { + ltCount++; + return ltCount === ltOccurrences.length ? '~' : match; + }); + } + } + } + this.text = this.text.charAt(0) + replacedRaw; + if (this.visibility === '~') { + this.text = this.text.replace('~', '\\~'); + } + } else if (count === 1 && this.visibility === '~') { + this.text = this.text.replace('~', '\\~'); } - this.text = replacedRaw; } } From 9ac20a5cb8a9bb75d786864e16f3a780f2b4c207 Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 11:00:31 -0700 Subject: [PATCH 006/155] Add styling compatibility to shape --- .../rendering-elements/shapes/classBox.ts | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts index 86fb40a627..fac9253b88 100644 --- a/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts +++ b/packages/mermaid/src/rendering-util/rendering-elements/shapes/classBox.ts @@ -1,21 +1,18 @@ -import { getNodeClasses } from './util.js'; +import { getNodeClasses, updateNodeBounds } from './util.js'; import { getConfig } from '$root/diagram-api/diagramAPI.js'; import { createText } from '../../createText.js'; import { select } from 'd3'; import type { Node } from '$root/rendering-util/types.d.ts'; import { evaluate } from '$root/diagrams/common/common.js'; import { calculateTextDimensions, calculateTextWidth } from '$root/utils.js'; -import { styles2String } from '$root/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js'; export const classBox = async (parent: SVGAElement, node: Node): Promise => { - const { labelStyles, nodeStyles } = styles2String(node); - node.labelStyle = labelStyles; + const styles = node.styles.join(';'); const mainGroup = parent .insert('g') - .attr('class', getNodeClasses(node)) - .attr('style', nodeStyles) - .attr('id', node.domId || node.id); + .attr('class', getNodeClasses(node)) // 'styleClass' + .attr('id', node.domId ?? node.id); let labelGroup = null; let membersGroup = null; let methodsGroup = null; @@ -25,12 +22,11 @@ export const classBox = async (parent: SVGAElement, node: Node): Promise 0 || node.methods.length > 0)) { mainGroup .insert('line') .attr('x1', 0 - PADDING) @@ -102,6 +97,7 @@ export const classBox = async (parent: SVGAElement, node: Node): Promise Date: Wed, 28 Aug 2024 12:24:42 -0700 Subject: [PATCH 007/155] Add support for classifiers in text attribute --- packages/mermaid/src/diagrams/class/classTypes.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/mermaid/src/diagrams/class/classTypes.ts b/packages/mermaid/src/diagrams/class/classTypes.ts index 4ac125fad7..adeae2aeb7 100644 --- a/packages/mermaid/src/diagrams/class/classTypes.ts +++ b/packages/mermaid/src/diagrams/class/classTypes.ts @@ -161,6 +161,12 @@ export class ClassMember { this.text = this.text.replace('~', '\\~'); } } + + if (this.classifier === '$') { + this.text = `${this.text}`; + } else if (this.classifier === '*') { + this.text = `${this.text}`; + } } parseClassifier() { From 97186504b5543eac6ef19d8ab61d945a594bdd7f Mon Sep 17 00:00:00 2001 From: yari-dewalt Date: Wed, 28 Aug 2024 12:25:25 -0700 Subject: [PATCH 008/155] Add classifier test diagram --- cypress/platform/yari.html | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cypress/platform/yari.html b/cypress/platform/yari.html index 4459aeb374..0046813eba 100644 --- a/cypress/platform/yari.html +++ b/cypress/platform/yari.html @@ -64,10 +64,20 @@

Only Class Name

Visibility and Types

(Further tilde testing)

- classDiagram class Duck{ ~interface~~~ +String beakColor #swim() ~quack()~~~ + classDiagram class Duck { ~interface~~~ +String beakColor #swim() ~quack()~~~ -test()~~~~~~~ +deposit(amount) bool }
+
+

Additional Classifiers

+

(* Abstract | $ Static)

+
+ classDiagram class Square~Shape~{ int id* List~int~ position* setPoints(List~int~ points)* + getPoints()* List~int~ } Square : -List~string~ messages* Square : + +setMessages(List~string~ messages)* Square : +getMessages()$ List~string~ Square : + +getDistanceMatrix() List~List~int~~ int$ +
+

Label


From b67c931f18e9942833ab08e433091c5645c516ea Mon Sep 17 00:00:00 2001
From: yari-dewalt 
Date: Wed, 28 Aug 2024 12:26:09 -0700
Subject: [PATCH 009/155] Update snapshot to include new data

---
 packages/mermaid/src/diagrams/class/classDiagram.spec.ts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts
index 9804b325ef..9def3ff1af 100644
--- a/packages/mermaid/src/diagrams/class/classDiagram.spec.ts
+++ b/packages/mermaid/src/diagrams/class/classDiagram.spec.ts
@@ -406,11 +406,14 @@ class C13["With Città foreign language"]
               "classifier": "",
               "id": "idCard : IdCard",
               "memberType": "attribute",
+              "text": "-idCard : IdCard",
               "visibility": "-",
             },
           ],
           "methods": [],
+          "shape": "classBox",
           "styles": [],
+          "text": "Student",
           "type": "",
         }
       `);

From b7790ba6b5cd862ace174725eda72b5eb5fd2eee Mon Sep 17 00:00:00 2001
From: yari-dewalt 
Date: Fri, 13 Sep 2024 12:40:59 -0700
Subject: [PATCH 010/155] Add diagrams for testing

---
 cypress/platform/yari.html | 264 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 259 insertions(+), 5 deletions(-)

diff --git a/cypress/platform/yari.html b/cypress/platform/yari.html
index 0046813eba..ec1ae90b49 100644
--- a/cypress/platform/yari.html
+++ b/cypress/platform/yari.html
@@ -13,6 +13,13 @@ 

Basic Class

}
+
+

Basic Class

+
+          flowchart TD
+            Start --> Stop
+        
+

Complex Class

@@ -72,10 +79,10 @@ 

Visibility and Types

Additional Classifiers

(* Abstract | $ Static)

- classDiagram class Square~Shape~{ int id* List~int~ position* setPoints(List~int~ points)* - getPoints()* List~int~ } Square : -List~string~ messages* Square : + classDiagram class Square~Shape~ { int id* List~int~ position* setPoints(List~int~ + points)* getPoints()* List~int~ } Square : -List~string~ messages$ Square : +setMessages(List~string~ messages)* Square : +getMessages()$ List~string~ Square : - +getDistanceMatrix() List~List~int~~ int$ + +getDistanceMatrix() List~List~int~~$
@@ -85,6 +92,64 @@

Label

class Animal~test~["Animal with a label"]
+
+

Spacing

+

(Fix ensures consistent spacing rules)

+

(No space or single space?)

+
+          classDiagram
+          class ClassName {
+          -attribute:type
+          -            attribute : type
+               test
+          
+          + GetAttribute() type                 
+          +     GetAttribute() type
+          }
+        
+
+
+

Annotation

+
+          classDiagram
+          class Shape
+          <<interface>> Shape
+          Shape : noOfVertices
+          Shape : draw()
+        
+
+
+

Long Class Name Text

+
+          classDiagram
+          class ThisIsATestForALongClassName {
+            <<interface>>
+            noOfLetters
+            delete()
+          }
+        
+
+
+

Long Annotation Text

+
+          classDiagram
+          class Shape
+          <<superlongannotationtext>> Shape
+          Shape : noOfVertices
+          Shape : draw()
+        
+
+
+

Long Member Text

+
+          classDiagram
+          class Shape
+          <<interface>> Shape
+          Shape : noOfVertices
+          Shape : longtexttestkeepgoingandgoing
+          Shape : draw()
+        
+

Link

@@ -101,6 +166,23 @@ 

Click

click Shape href "https://www.github.com" "This is a tooltip for a link"
+
+

Hand Drawn

+
+          ---
+          config:
+            look: handDrawn
+            htmlLabels: true
+          ---
+          classDiagram
+          class Hand {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+          style Hand fill:#f9f,stroke:#29f,stroke-width:2px
+        
+

Neutral Theme

@@ -198,7 +280,28 @@ 

Styling within Diagram

-

Styling with Class

+

Styling with classDef Statement

+
+          classDiagram
+          class Duck:::bold {
+            +String beakColor
+            +swim()
+            +quack()
+          }
+
+          class Dog {
+            +int numTeeth
+            +bark()
+          }
+
+          cssClass "Duck,Dog" pink
+
+          classDef pink fill:#f9f
+          classDef bold stroke:#333,stroke-width:6px,color:#fff
+        
+
+
+

Styling with Class in Stylesheet

           classDiagram
           class Duck {
@@ -265,6 +368,156 @@ 

Class Nodes LR

}
+
+

Relations

+
+          classDiagram
+            classA <|-- classB
+            classC *-- classD
+            classE o-- classF
+            classG <-- classH
+            classI -- classJ
+            classK <.. classL
+            classM <|.. classN
+            classO .. classP
+        
+
+
+

Two Way Relation

+
+          classDiagram
+          class Animal {
+            int size
+            walk()
+          }
+          class Zebra {
+            int size
+            walk()
+          }
+            Animal o--|> Zebra
+
+        
+
+
+

Relations with Labels

+
+          classDiagram
+            classA <|-- classB : implements
+            classC *-- classD : composition
+            classE o-- classF : aggregation
+        
+
+
+

Cardinality / Multiplicity

+
+          classDiagram
+            Customer "1" --> "*" Ticket
+            Student "1" --> "1..*" Course
+            Galaxy --> "many" Star : Contains
+        
+
+
+

Complex Relations with Theme

+
+          ---
+          config:
+            theme: forest
+            look: handDrawn
+          ---
+          classDiagram
+            direction RL
+            class Student {
+              -idCard : IdCard
+            }
+            class IdCard{
+              -id : int
+              -name : string
+            }
+            class Bike{
+              -id : int
+              -name : string
+            }
+            Student "1" --o "1" IdCard : carries
+            Student "1" --o "1" Bike : rides
+        
+
+
+

Notes

+
+          classDiagram
+            note "This is a general note"
+            note for MyClass "This is a note for a class"
+            class MyClass
+        
+
+
+

Namespaces

+
+          classDiagram
+            namespace BaseShapes {
+                class Triangle
+                class Rectangle {
+                  double width
+                  double height
+                }
+            }
+        
+
+
+

Full Example

+
+          ---
+          title: Animal example
+          ---
+          classDiagram
+              note "From Duck till Zebra"
+              Animal <|--|> Duck
+              note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
+              Animal <|-- Fish
+              Animal <|--|> Zebra
+              Animal : +int age
+              Animal : +String gender
+              Animal: +isMammal()
+              Animal: +mate()
+              class Duck{
+                  +String beakColor
+                  +swim()
+                  +quack()
+              }
+              class Fish{
+                  -int sizeInFeet
+                  -canEat()
+              }
+              class Zebra{
+                  +bool is_wild
+                  +run()
+              }
+        
+
+
+

Full Example

+
+          ---
+            config:
+              theme: forest
+              look: handDrawn
+          ---
+          classDiagram
+          note for Outside "Note testing"
+          namespace Test {
+              class Outside
+          }
+          namespace BaseShapes {
+              class Triangle
+              class Rectangle {
+                double width
+                double height
+              }
+          }
+          Outside <|--|> Rectangle
+          style Triangle fill:#f9f,stroke:#333,stroke-width:4px
+        
+