Merge branch 'develop' into feature/5114_add_parallel_commit_config

This commit is contained in:
Matheus B 2023-12-22 21:32:20 -03:00
commit 46583cf4eb
32 changed files with 1208 additions and 628 deletions

View File

@ -6,6 +6,6 @@ export default {
// https://prettier.io/docs/en/cli.html#--cache
'prettier --write',
],
'cSpell.json': ['ts-node-esm scripts/fixCSpell.ts'],
'cSpell.json': ['tsx scripts/fixCSpell.ts'],
'**/*.jison': ['pnpm -w run lint:jison'],
};

View File

@ -10,3 +10,6 @@ stats
.nyc_output
# Autogenerated by `pnpm run --filter mermaid types:build-config`
packages/mermaid/src/config.type.ts
# Ignore the files creates in /demos/dev except for example.html
demos/dev/**
!/demos/dev/example.html

3
.vscode/launch.json vendored
View File

@ -18,7 +18,8 @@
"type": "node",
"request": "launch",
"args": ["scripts/docs.cli.mts"],
"runtimeArgs": ["--loader", "ts-node/esm"],
// we'll need to change this to --import in Node.JS v20.6.0 and up
"runtimeArgs": ["--loader", "tsx/esm"],
"cwd": "${workspaceRoot}/packages/mermaid",
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
"smartStep": true,

View File

@ -571,4 +571,14 @@ class C13["With Città foreign language"]
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
it('should render a simple class diagram with style definition', () => {
imgSnapshotTest(
`
classDiagram-v2
class Class10
style Class10 fill:#f9f,stroke:#333,stroke-width:4px
`,
{ logLevel: 1, flowchart: { htmlLabels: false } }
);
});
});

View File

@ -811,7 +811,22 @@ gitGraph TB:
{}
);
});
it('40: should render default GitGraph with parallelCommits set to false', () => {
it('40: should render a simple gitgraph with cherry pick merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
cherry-pick id: "M" parent:"B"`
);
});
it('41: should render default GitGraph with parallelCommits set to false', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
@ -830,7 +845,7 @@ gitGraph TB:
{ gitGraph: { parallelCommits: false } }
);
});
it('41: should render GitGraph with parallel commits', () => {
it('42: should render GitGraph with parallel commits', () => {
imgSnapshotTest(
`gitGraph
commit id:"1-abcdefg"
@ -849,7 +864,7 @@ gitGraph TB:
{ gitGraph: { parallelCommits: true } }
);
});
it('42: should render GitGraph with parallel commits | Vertical Branch', () => {
it('43: should render GitGraph with parallel commits | Vertical Branch', () => {
imgSnapshotTest(
`gitGraph TB:
commit id:"1-abcdefg"

View File

@ -33,6 +33,7 @@
---
config:
sankey:
useMaxWidth: true
showValues: false
width: 1200
height: 600

View File

@ -1,7 +1,7 @@
version: '3.9'
services:
mermaid:
image: node:18.18.2-alpine3.18
image: node:18.19.0-alpine3.18
stdin_open: true
tty: true
working_dir: /mermaid

View File

@ -111,6 +111,8 @@ Communication tools and platforms
### Wikis
- [PmWiki](https://www.pmwiki.org)
- [MermaidJs Cookbook recipe](https://www.pmwiki.org/wiki/Cookbook/MermaidJs)
- [MediaWiki](https://www.mediawiki.org)
- [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
- [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
@ -234,5 +236,5 @@ Communication tools and platforms
- [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io)
- [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams)
- [ui.markdown(..., extras=\['mermaid'\])](https://nicegui.io/reference#markdown_element)
- [ui.mermaid(...)](https://nicegui.io/documentation/section_text_elements#markdown_element)
- [ui.markdown(..., extras=\['mermaid'\])](https://nicegui.io/documentation/section_text_elements#mermaid_diagrams)

View File

@ -240,9 +240,9 @@ class BankAccount{
#### Generic Types
Members can be defined using generic types, such as `List<int>`, for fields, parameters, and return types by enclosing the type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported.
Generics can be representated as part of a class definition, and for class members/return types. In order to denote an item as generic, you enclose that type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported, though generics that include a comma are currently not supported. (such as `List<List<K, V>>`)
Generics can be represented as part of a class definition and also in the parameters or the return value of a method/function:
> _note_ when a generic is used within a class definition, the generic type is NOT considered part of the class name. i.e.: for any syntax which required you to reference the class name, you need to drop the type part of the definition. This also means that mermaid does not currently support having two classes with the same name, but different generic types.
```mermaid-example
classDiagram
@ -766,9 +766,30 @@ Beginner's tip—a full example using interactive links in an HTML page:
## Styling
### Styling a node
### Styling a node (v\<MERMAID_RELEASE_VERSION>+)
It is possible to apply specific styles such as a thicker border or a different background color to individual nodes. This is done by predefining classes in css styles that can be applied from the graph definition using the `cssClass` statement or the `:::` short hand.
It is possible to apply specific styles such as a thicker border or a different background color to an individual node using the `style` keyword.
```mermaid-example
classDiagram
class Animal
class Mineral
style Animal fill:#f9f,stroke:#333,stroke-width:4px
style Mineral fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
```mermaid
classDiagram
class Animal
class Mineral
style Animal fill:#f9f,stroke:#333,stroke-width:4px
style Mineral fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
#### Classes
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. This is done by predefining classes in css styles that can be applied from the graph definition using the `cssClass` statement or the `:::` short hand.
```html
<style>

View File

@ -366,41 +366,49 @@ A few important rules to note here are:
1. You need to provide the `id` for an existing commit to be cherry-picked. If given commit id does not exist it will result in an error. For this, make use of the `commit id:$value` format of declaring commits. See the examples from above.
2. The given commit must not exist on the current branch. The cherry-picked commit must always be a different branch than the current branch.
3. Current branch must have at least one commit, before you can cherry-pick, otherwise it will cause an error is throw.
4. When cherry-picking a merge commit, providing a parent commit ID is mandatory. If the parent attribute is omitted or an invalid parent commit ID is provided, an error will be thrown.
5. The specified parent commit must be an immediate parent of the merge commit being cherry-picked.
Let see an example:
```mermaid-example
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
commit id: "ZERO"
branch develop
branch release
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
merge develop id:"MERGE"
commit id:"TWO"
checkout release
cherry-pick id:"MERGE" parent:"B"
commit id:"THREE"
checkout develop
commit id:"C"
```
```mermaid
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
commit id: "ZERO"
branch develop
branch release
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
merge develop id:"MERGE"
commit id:"TWO"
checkout release
cherry-pick id:"MERGE" parent:"B"
commit id:"THREE"
checkout develop
commit id:"C"
```
## Gitgraph specific configuration options

View File

@ -4,7 +4,7 @@
"version": "10.2.4",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"type": "module",
"packageManager": "pnpm@8.11.0",
"packageManager": "pnpm@8.12.0",
"keywords": [
"diagram",
"markdown",
@ -15,26 +15,26 @@
"git graph"
],
"scripts": {
"build:vite": "ts-node-esm --transpileOnly .vite/build.ts",
"build:vite": "tsx .vite/build.ts",
"build:mermaid": "pnpm build:vite --mermaid",
"build:viz": "pnpm build:mermaid --visualize",
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-zenuml/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly",
"build:types:watch": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly --watch",
"build:watch": "pnpm build:vite --watch",
"build": "pnpm run -r clean && pnpm build:types && pnpm build:vite",
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"",
"dev": "concurrently \"pnpm build:vite --watch\" \"tsx .vite/server.ts\"",
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev",
"release": "pnpm build",
"lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
"lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts",
"lint:jison": "ts-node-esm ./scripts/jison/lint.mts",
"contributors": "ts-node-esm scripts/updateContributors.ts",
"lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && tsx scripts/fixCSpell.ts",
"lint:jison": "tsx ./scripts/jison/lint.mts",
"contributors": "tsx scripts/updateContributors.ts",
"cypress": "cypress run",
"cypress:open": "cypress open",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"coverage:cypress:clean": "rimraf .nyc_output coverage/cypress",
"e2e:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm e2e",
"coverage:merge": "ts-node-esm scripts/coverage.ts",
"coverage:merge": "tsx scripts/coverage.ts",
"coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge",
"ci": "vitest run",
"test": "pnpm lint && vitest run",
@ -116,14 +116,14 @@
"rimraf": "^5.0.0",
"rollup-plugin-visualizer": "^5.9.2",
"start-server-and-test": "^2.0.0",
"ts-node": "^10.9.1",
"tsx": "^4.6.2",
"typescript": "^5.1.3",
"vite": "^4.3.9",
"vite": "^4.4.12",
"vite-plugin-istanbul": "^4.1.0",
"vitest": "^0.34.0"
},
"volta": {
"node": "18.18.2"
"node": "18.19.0"
},
"nyc": {
"report-dir": "coverage/cypress"

View File

@ -26,18 +26,18 @@
"clean": "rimraf dist",
"dev": "pnpm -w dev",
"docs:code": "typedoc src/defaultConfig.ts src/config.ts src/mermaidAPI.ts && prettier --write ./src/docs/config/setup",
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && ts-node-esm scripts/docs.cli.mts",
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && ts-node-esm scripts/docs.cli.mts --verify",
"docs:pre:vitepress": "pnpm --filter ./src/docs prefetch && rimraf src/vitepress && pnpm docs:code && ts-node-esm scripts/docs.cli.mts --vitepress && pnpm --filter ./src/vitepress install --no-frozen-lockfile --ignore-scripts",
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts",
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts --verify",
"docs:pre:vitepress": "pnpm --filter ./src/docs prefetch && rimraf src/vitepress && pnpm docs:code && tsx scripts/docs.cli.mts --vitepress && pnpm --filter ./src/vitepress install --no-frozen-lockfile --ignore-scripts",
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"ts-node-esm scripts/docs.cli.mts --watch --vitepress\"",
"docs:dev:docker": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev:docker\" \"ts-node-esm scripts/docs.cli.mts --watch --vitepress\"",
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
"docs:dev:docker": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev:docker\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
"docs:serve": "pnpm docs:build:vitepress && vitepress serve src/vitepress",
"docs:spellcheck": "cspell --config ../../cSpell.json \"src/docs/**/*.md\"",
"docs:release-version": "ts-node-esm scripts/update-release-version.mts",
"docs:verify-version": "ts-node-esm scripts/update-release-version.mts --verify",
"types:build-config": "ts-node-esm --transpileOnly scripts/create-types-from-json-schema.mts",
"types:verify-config": "ts-node-esm scripts/create-types-from-json-schema.mts --verify",
"docs:release-version": "tsx scripts/update-release-version.mts",
"docs:verify-version": "tsx scripts/update-release-version.mts --verify",
"types:build-config": "tsx scripts/create-types-from-json-schema.mts",
"types:verify-config": "tsx scripts/create-types-from-json-schema.mts --verify",
"checkCircle": "npx madge --circular ./src",
"release": "pnpm build",
"prepublishOnly": "cpy '../../README.*' ./ --cwd=. && pnpm docs:release-version && pnpm -w run build"

View File

@ -68,6 +68,11 @@ export interface MermaidConfig {
* The maximum allowed size of the users text diagram
*/
maxTextSize?: number;
/**
* Defines the maximum number of edges that can be drawn in a graph.
*
*/
maxEdges?: number;
darkMode?: boolean;
htmlLabels?: boolean;
/**

View File

@ -1013,6 +1013,7 @@ const class_box = (parent, node) => {
});
rect
.attr('style', node.style)
.attr('class', 'outer title-state')
.attr('x', -maxWidth / 2 - halfPadding)
.attr('y', -(maxHeight / 2) - halfPadding)

View File

@ -84,6 +84,7 @@ export const addClass = function (_id: string) {
methods: [],
members: [],
annotations: [],
styles: [],
domId: MERMAID_DOM_ID_PREFIX + name + '-' + classCounter,
} as ClassNode;
@ -214,7 +215,7 @@ export const cleanupLabel = function (label: string) {
};
/**
* Called by parser when a special node is found, e.g. a clickable element.
* Called by parser when assigning cssClass to a class
*
* @param ids - Comma separated list of ids
* @param className - Class to add
@ -446,11 +447,27 @@ const getNamespaces = function (): NamespaceMap {
* @public
*/
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];
});
if (namespaces[id] === undefined) {
return;
}
for (const name of classNames) {
const { className } = splitClassNameAndType(name);
classes[className].parent = id;
namespaces[id].classes[className] = classes[className];
}
};
export const setCssStyle = function (id: string, styles: string[]) {
const thisClass = classes[id];
if (!styles || !thisClass) {
return;
}
for (const s of styles) {
if (s.includes(',')) {
thisClass.styles.push(...s.split(','));
} else {
thisClass.styles.push(s);
}
}
};
@ -490,4 +507,5 @@ export default {
addClassesToNamespace,
getNamespace,
getNamespaces,
setCssStyle,
};

View File

@ -56,5 +56,18 @@ describe('class diagram, ', function () {
expect(parser.yy.getClass('Class01').cssClasses[0]).toBe('exClass');
expect(parser.yy.getClass('Class02').cssClasses[0]).toBe('exClass');
});
it('should be possible to apply a style to an individual node', function () {
const str =
'classDiagram\n' +
'class Class01\n class Class02\n style Class01 fill:#f9f,stroke:#333,stroke-width:4px';
parser.parse(str);
const styleElements = parser.yy.getClass('Class01').styles;
expect(styleElements[0]).toBe('fill:#f9f');
expect(styleElements[1]).toBe('stroke:#333');
expect(styleElements[2]).toBe('stroke-width:4px');
});
});
});

View File

@ -409,6 +409,7 @@ class C13["With Città foreign language"]
},
],
"methods": [],
"styles": [],
"type": "",
}
`);
@ -1043,6 +1044,19 @@ foo()
`;
parser.parse(str);
});
it('should handle namespace with generic types', () => {
parser.parse(`classDiagram
namespace space {
class Square~Shape~{
int id
List~int~ position
setPoints(List~int~ points)
getPoints() List~int~
}
}`);
});
});
});

View File

@ -104,7 +104,7 @@ export const addClasses = function (
*/
const cssClassStr = vertex.cssClasses.join(' ');
const styles = { labelStyle: '', style: '' }; //getStylesFromArray(vertex.styles);
const styles = 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;

View File

@ -10,6 +10,7 @@ export interface ClassNode {
members: ClassMember[];
annotations: string[];
domId: string;
styles: string[];
parent?: string;
link?: string;
linkTarget?: string;

View File

@ -60,6 +60,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
<string>["] this.popState();
<string>[^"]* return "STR";
<*>["] this.begin("string");
"style" return 'STYLE';
<INITIAL,namespace>"namespace" { this.begin('namespace'); return 'NAMESPACE'; }
<namespace>\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; }
@ -127,6 +128,10 @@ line was introduced with 'click'.
<*>\- return 'MINUS';
<*>"." return 'DOT';
<*>\+ return 'PLUS';
":" return 'COLON';
"," return 'COMMA';
\# return 'BRKT';
"#" return 'BRKT';
<*>\% return 'PCT';
<*>"=" return 'EQUALS';
<*>\= return 'EQUALS';
@ -198,6 +203,7 @@ line was introduced with 'click'.
[\uFFD2-\uFFD7\uFFDA-\uFFDC]
return 'UNICODE_TEXT';
<*>\s return 'SPACE';
\s return 'SPACE';
<*><<EOF>> return 'EOF';
/lex
@ -254,6 +260,7 @@ statement
| memberStatement
| annotationStatement
| clickStatement
| styleStatement
| cssClassStatement
| noteStatement
| direction
@ -365,10 +372,26 @@ clickStatement
| CLICK className HREF STR STR LINK_TARGET {$$ = $1;yy.setLink($2, $4, $6);yy.setTooltip($2, $5);}
;
cssClassStatement
: CSSCLASS STR alphaNumToken {yy.setCssClass($2, $3);}
styleStatement
:STYLE ALPHA stylesOpt {$$ = $STYLE;yy.setCssStyle($2,$stylesOpt);}
;
cssClassStatement
: CSSCLASS STR ALPHA {yy.setCssClass($2, $3);}
;
stylesOpt
: style {$$ = [$style]}
| stylesOpt COMMA style {$stylesOpt.push($style);$$ = $stylesOpt;}
;
style
: styleComponent
| style styleComponent {$$ = $style + $styleComponent;}
;
styleComponent: ALPHA | NUM | COLON | UNIT | SPACE | BRKT | STYLE | PCT | LABEL;
commentToken : textToken | graphCodeTokens ;
textToken : textNoTagsToken | TAGSTART | TAGEND | '==' | '--' | PCT | DEFAULT;

View File

@ -12,7 +12,6 @@ import {
setDiagramTitle,
getDiagramTitle,
} from '../common/commonDb.js';
import errorDiagram from '../error/errorDiagram.js';
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
let vertexCounter = 0;
@ -92,7 +91,6 @@ export const addVertex = function (_id, textObj, type, style, classes, dir, prop
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
txt = txt.substring(1, txt.length - 1);
}
vertices[id].text = txt;
} else {
if (vertices[id].text === undefined) {
@ -160,11 +158,17 @@ export const addSingleLink = function (_start, _end, type) {
if (edge?.length > 10) {
edge.length = 10;
}
if (edges.length < 280) {
if (edges.length < (config.maxEdges ?? 500)) {
log.info('abc78 pushing edge...');
edges.push(edge);
} else {
throw new Error('Too many edges');
throw new Error(
`Edge limit exceeded. ${edges.length} edges found, but the limit is ${config.maxEdges}.
Initialize mermaid with maxEdges set to a higher number to allow more edges.
You cannot set this config via configuration inside the diagram as it is a secure config.
You have to call mermaid.initialize.`
);
}
};
export const addLink = function (_start, _end, type) {
@ -460,6 +464,7 @@ export const clear = function (ver = 'gen-1') {
tooltips = {};
firstGraphFlag = true;
version = ver;
config = getConfig();
commonClear();
};
export const setGen = (ver) => {

View File

@ -255,11 +255,12 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag
log.debug('in mergeBranch');
};
export const cherryPick = function (sourceId, targetId, tag) {
export const cherryPick = function (sourceId, targetId, tag, parentCommitId) {
log.debug('Entering cherryPick:', sourceId, targetId, tag);
sourceId = common.sanitizeText(sourceId, getConfig());
targetId = common.sanitizeText(targetId, getConfig());
tag = common.sanitizeText(tag, getConfig());
parentCommitId = common.sanitizeText(parentCommitId, getConfig());
if (!sourceId || commits[sourceId] === undefined) {
let error = new Error(
@ -274,20 +275,21 @@ export const cherryPick = function (sourceId, targetId, tag) {
};
throw error;
}
let sourceCommit = commits[sourceId];
let sourceCommitBranch = sourceCommit.branch;
if (sourceCommit.type === commitType.MERGE) {
if (
parentCommitId &&
!(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))
) {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit should not be a merge commit'
'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
);
throw error;
}
if (sourceCommit.type === commitType.MERGE && !parentCommitId) {
let error = new Error(
'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
if (!targetId || commits[targetId] === undefined) {
@ -327,7 +329,11 @@ export const cherryPick = function (sourceId, targetId, tag) {
parents: [head == null ? null : head.id, sourceCommit.id],
branch: curBranch,
type: commitType.CHERRY_PICK,
tag: tag ?? 'cherry-pick:' + sourceCommit.id,
tag:
tag ??
`cherry-pick:${sourceCommit.id}${
sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : ''
}`,
};
head = commit;
commits[commit.id] = commit;

View File

@ -673,6 +673,145 @@ describe('when parsing a gitGraph', function () {
expect(commits[cherryPickCommitID].branch).toBe('main');
});
it('should support cherry-picking of merge commits', function () {
const str = `gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
cherry-pick id: "M" parent:"B"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
const cherryPickCommitID = Object.keys(commits)[4];
expect(commits[cherryPickCommitID].tag).toBe('cherry-pick:M|parent:B');
expect(commits[cherryPickCommitID].branch).toBe('release');
});
it('should support cherry-picking of merge commits with tag', function () {
const str = `gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
cherry-pick id: "M" parent:"ZERO" tag: "v1.0"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
const cherryPickCommitID = Object.keys(commits)[4];
expect(commits[cherryPickCommitID].tag).toBe('v1.0');
expect(commits[cherryPickCommitID].branch).toBe('release');
});
it('should support cherry-picking of merge commits with additional commit', function () {
const str = `gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
commit id: "C"
cherry-pick id: "M" tag: "v2.1:ZERO" parent:"ZERO"
commit id: "D"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
const cherryPickCommitID = Object.keys(commits)[5];
expect(commits[cherryPickCommitID].tag).toBe('v2.1:ZERO');
expect(commits[cherryPickCommitID].branch).toBe('release');
});
it('should support cherry-picking of merge commits with empty tag', function () {
const str = `gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
commit id: "C"
cherry-pick id:"M" parent: "ZERO" tag:""
commit id: "D"
cherry-pick id:"M" tag:"" parent: "B"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
const cherryPickCommitID = Object.keys(commits)[5];
const cherryPickCommitID2 = Object.keys(commits)[7];
expect(commits[cherryPickCommitID].tag).toBe('');
expect(commits[cherryPickCommitID2].tag).toBe('');
expect(commits[cherryPickCommitID].branch).toBe('release');
});
it('should fail cherry-picking of merge commits if the parent of merge commits is not specified', function () {
expect(() =>
parser
.parse(
`gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
commit id: "C"
cherry-pick id:"M"
`
)
.toThrow(
'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
)
);
});
it('should fail cherry-picking of merge commits when the parent provided is not an immediate parent of cherry picked commit', function () {
expect(() =>
parser
.parse(
`gitGraph
commit id: "ZERO"
branch feature
branch release
checkout feature
commit id: "A"
commit id: "B"
checkout main
merge feature id: "M"
checkout release
commit id: "C"
cherry-pick id:"M" parent: "A"
`
)
.toThrow(
'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
)
);
});
it('should throw error when try to branch existing branch: main', function () {
const str = `gitGraph
commit

View File

@ -39,6 +39,7 @@ branch(?=\s|$) return 'BRANCH';
"order:" return 'ORDER';
merge(?=\s|$) return 'MERGE';
cherry\-pick(?=\s|$) return 'CHERRY_PICK';
"parent:" return 'PARENT_COMMIT'
// "reset" return 'RESET';
checkout(?=\s|$) return 'CHECKOUT';
"LR" return 'DIR';
@ -109,10 +110,17 @@ branchStatement
cherryPickStatement
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3, '', undefined)}
| CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR {yy.cherryPick($3, '', undefined,$5)}
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG STR {yy.cherryPick($3, '', $5)}
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG EMPTYSTR {yy.cherryPick($3, '', '')}
| CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR COMMIT_TAG STR {yy.cherryPick($3, '', $7,$5)}
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG STR PARENT_COMMIT STR {yy.cherryPick($3, '', $5,$7)}
| CHERRY_PICK COMMIT_TAG STR COMMIT_ID STR {yy.cherryPick($5, '', $3)}
| CHERRY_PICK COMMIT_TAG EMPTYSTR COMMIT_ID STR {yy.cherryPick($3, '', '')}
| CHERRY_PICK COMMIT_TAG EMPTYSTR COMMIT_ID STR {yy.cherryPick($5, '', '')}
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG EMPTYSTR {yy.cherryPick($3, '', '')}
| CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR COMMIT_TAG EMPTYSTR {yy.cherryPick($3, '', '',$5)}
| CHERRY_PICK COMMIT_ID STR COMMIT_TAG EMPTYSTR PARENT_COMMIT STR {yy.cherryPick($3, '', '',$7)}
| CHERRY_PICK COMMIT_TAG STR COMMIT_ID STR PARENT_COMMIT STR {yy.cherryPick($5, '', $3,$7)}
| CHERRY_PICK COMMIT_TAG EMPTYSTR COMMIT_ID STR PARENT_COMMIT STR{yy.cherryPick($5, '', '',$7)}
;
mergeStatement

View File

@ -16,7 +16,7 @@ import {
sankeyCenter as d3SankeyCenter,
sankeyJustify as d3SankeyJustify,
} from 'd3-sankey';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
import { Uid } from '../../rendering-util/uid.js';
import type { SankeyNodeAlignment } from '../../config.type.js';
@ -70,12 +70,6 @@ export const draw = function (text: string, id: string, _version: string, diagOb
const suffix = conf?.suffix ?? defaultSankeyConfig.suffix!;
const showValues = conf?.showValues ?? defaultSankeyConfig.showValues!;
// FIX: using max width prevents height from being set, is it intended?
// to add height directly one can use `svg.attr('height', height)`
//
// @ts-ignore TODO: svg type vs selection mismatch
configureSvgSize(svg, height, width, useMaxWidth);
// Prepare data for construction based on diagObj.db
// This must be a mutable object with `nodes` and `links` properties:
//
@ -208,6 +202,8 @@ export const draw = function (text: string, id: string, _version: string, diagOb
.attr('d', d3SankeyLinkHorizontal())
.attr('stroke', coloring)
.attr('stroke-width', (d: any) => Math.max(1, d.width));
setupGraphViewbox(undefined, svg, 0, useMaxWidth);
};
export default {

View File

@ -109,6 +109,8 @@ Communication tools and platforms
### Wikis
- [PmWiki](https://www.pmwiki.org)
- [MermaidJs Cookbook recipe](https://www.pmwiki.org/wiki/Cookbook/MermaidJs)
- [MediaWiki](https://www.mediawiki.org)
- [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
- [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
@ -232,5 +234,5 @@ Communication tools and platforms
- [ExDoc](https://github.com/elixir-lang/ex_doc)
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io)
- [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams)
- [ui.markdown(..., extras=['mermaid'])](https://nicegui.io/reference#markdown_element)
- [ui.mermaid(...)](https://nicegui.io/documentation/section_text_elements#markdown_element)
- [ui.markdown(..., extras=['mermaid'])](https://nicegui.io/documentation/section_text_elements#mermaid_diagrams)

View File

@ -11,8 +11,8 @@
"preview-https": "pnpm build && serve .vitepress/dist",
"preview-https-no-prefetch": "pnpm build-no-prefetch && serve .vitepress/dist",
"prefetch": "pnpm fetch-contributors && pnpm fetch-avatars",
"fetch-avatars": "ts-node-esm .vitepress/scripts/fetch-avatars.ts",
"fetch-contributors": "ts-node-esm .vitepress/scripts/fetch-contributors.ts"
"fetch-avatars": "tsx .vitepress/scripts/fetch-avatars.ts",
"fetch-contributors": "tsx .vitepress/scripts/fetch-contributors.ts"
},
"dependencies": {
"@vueuse/core": "^10.1.0",
@ -22,15 +22,15 @@
},
"devDependencies": {
"@iconify-json/carbon": "^1.1.16",
"@unocss/reset": "^0.57.0",
"@unocss/reset": "^0.58.0",
"@vite-pwa/vitepress": "^0.3.0",
"@vitejs/plugin-vue": "^4.2.1",
"fast-glob": "^3.2.12",
"https-localhost": "^4.7.1",
"pathe": "^1.1.0",
"unocss": "^0.57.0",
"unplugin-vue-components": "^0.25.0",
"vite": "^4.3.9",
"unocss": "^0.58.0",
"unplugin-vue-components": "^0.26.0",
"vite": "^4.4.12",
"vite-plugin-pwa": "^0.17.0",
"vitepress": "1.0.0-rc.31",
"workbox-window": "^7.0.0"

View File

@ -143,9 +143,9 @@ class BankAccount{
#### Generic Types
Members can be defined using generic types, such as `List<int>`, for fields, parameters, and return types by enclosing the type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported.
Generics can be representated as part of a class definition, and for class members/return types. In order to denote an item as generic, you enclose that type within `~` (**tilde**). **Nested** type declarations such as `List<List<int>>` are supported, though generics that include a comma are currently not supported. (such as `List<List<K, V>>`)
Generics can be represented as part of a class definition and also in the parameters or the return value of a method/function:
> _note_ when a generic is used within a class definition, the generic type is NOT considered part of the class name. i.e.: for any syntax which required you to reference the class name, you need to drop the type part of the definition. This also means that mermaid does not currently support having two classes with the same name, but different generic types.
```mermaid-example
classDiagram
@ -518,9 +518,22 @@ Beginner's tip—a full example using interactive links in an HTML page:
## Styling
### Styling a node
### Styling a node (v<MERMAID_RELEASE_VERSION>+)
It is possible to apply specific styles such as a thicker border or a different background color to individual nodes. This is done by predefining classes in css styles that can be applied from the graph definition using the `cssClass` statement or the `:::` short hand.
It is possible to apply specific styles such as a thicker border or a different background color to an individual node using the `style` keyword.
```mermaid-example
classDiagram
class Animal
class Mineral
style Animal fill:#f9f,stroke:#333,stroke-width:4px
style Mineral fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
```
#### Classes
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. This is done by predefining classes in css styles that can be applied from the graph definition using the `cssClass` statement or the `:::` short hand.
```html
<style>

View File

@ -244,24 +244,29 @@ A few important rules to note here are:
1. You need to provide the `id` for an existing commit to be cherry-picked. If given commit id does not exist it will result in an error. For this, make use of the `commit id:$value` format of declaring commits. See the examples from above.
2. The given commit must not exist on the current branch. The cherry-picked commit must always be a different branch than the current branch.
3. Current branch must have at least one commit, before you can cherry-pick, otherwise it will cause an error is throw.
4. When cherry-picking a merge commit, providing a parent commit ID is mandatory. If the parent attribute is omitted or an invalid parent commit ID is provided, an error will be thrown.
5. The specified parent commit must be an immediate parent of the merge commit being cherry-picked.
Let see an example:
```mermaid-example
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
commit id: "ZERO"
branch develop
branch release
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
merge develop id:"MERGE"
commit id:"TWO"
checkout release
cherry-pick id:"MERGE" parent:"B"
commit id:"THREE"
checkout develop
commit id:"C"
```
## Gitgraph specific configuration options

View File

@ -74,6 +74,12 @@ properties:
description: The maximum allowed size of the users text diagram
type: number
default: 50000
maxEdges:
description: |
Defines the maximum number of edges that can be drawn in a graph.
type: integer
default: 500
minimum: 0
darkMode:
type: boolean
default: false
@ -156,7 +162,7 @@ properties:
in the current `currentConfig`.
This prevents malicious graph directives from overriding a site's default security.
default: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize']
default: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize', 'maxEdges']
type: array
items:
type: string

View File

@ -45,6 +45,7 @@ export const configureSvgSize = function (svgElem, height, width, useMaxWidth) {
d3Attrs(svgElem, attrs);
};
// TODO v11: Remove the graph parameter. It is not used.
export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) {
const svgBounds = svgElem.node().getBBox();
const sWidth = svgBounds.width;

File diff suppressed because it is too large Load Diff