From 594f2180a017107d17b1dcb4d8eb86b96c728cef Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 11:33:17 -0700 Subject: [PATCH 1/9] feat: implement multiple tags --- .../mermaid/src/diagrams/git/gitGraphAst.js | 23 ++-- .../src/diagrams/git/gitGraphParserV2.spec.js | 20 +-- .../src/diagrams/git/gitGraphRenderer.js | 122 +++++++++++------- .../src/diagrams/git/parser/gitGraph.jison | 26 ++-- 4 files changed, 113 insertions(+), 78 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphAst.js b/packages/mermaid/src/diagrams/git/gitGraphAst.js index 0997f65b1..ca9bbb010 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphAst.js +++ b/packages/mermaid/src/diagrams/git/gitGraphAst.js @@ -113,7 +113,7 @@ export const commit = function (msg, id, type, tag) { message: msg, seq: seq++, type: type ? type : commitType.NORMAL, - tag: tag ? tag : '', + tags: tag ? [tag] : [], parents: head == null ? [] : [head.id], branch: curBranch, }; @@ -147,7 +147,7 @@ export const branch = function (name, order) { } }; -export const merge = function (otherBranch, custom_id, override_type, custom_tag) { +export const merge = function (otherBranch, custom_id, override_type, custom_tags) { otherBranch = common.sanitizeText(otherBranch, getConfig()); custom_id = common.sanitizeText(custom_id, getConfig()); @@ -216,12 +216,19 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag ' already exists, use different custom Id' ); error.hash = { - text: 'merge ' + otherBranch + custom_id + override_type + custom_tag, - token: 'merge ' + otherBranch + custom_id + override_type + custom_tag, + text: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join(','), + token: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join(','), line: '1', loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 }, expected: [ - 'merge ' + otherBranch + ' ' + custom_id + '_UNIQUE ' + override_type + ' ' + custom_tag, + 'merge ' + + otherBranch + + ' ' + + custom_id + + '_UNIQUE ' + + override_type + + ' ' + + custom_tags.join(','), ], }; @@ -245,7 +252,7 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag type: commitType.MERGE, customType: override_type, customId: custom_id ? true : false, - tag: custom_tag ? custom_tag : '', + tags: custom_tags ? custom_tags : [], }; head = commit; commits[commit.id] = commit; @@ -329,11 +336,11 @@ export const cherryPick = function (sourceId, targetId, tag, parentCommitId) { parents: [head == null ? null : head.id, sourceCommit.id], branch: curBranch, type: commitType.CHERRY_PICK, - tag: - tag ?? + tags: tag ? [tag] : [ `cherry-pick:${sourceCommit.id}${ sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : '' }`, + ], }; head = commit; commits[commit.id] = commit; diff --git a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js index ac85712b2..53e69c620 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js +++ b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js @@ -20,7 +20,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(0); }); @@ -37,7 +37,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(0); }); @@ -73,7 +73,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(2); }); @@ -91,7 +91,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(1); }); @@ -109,7 +109,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(0); }); @@ -127,7 +127,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test commit'); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(0); }); @@ -145,7 +145,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test commit'); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe(''); + expect(commits[key].tag).toBe([]); expect(commits[key].type).toBe(0); }); @@ -741,7 +741,7 @@ describe('when parsing a gitGraph', function () { parser.parse(str); const commits = parser.yy.getCommits(); const cherryPickCommitID = Object.keys(commits)[2]; - expect(commits[cherryPickCommitID].tag).toBe(''); + expect(commits[cherryPickCommitID].tag).toBe([]); expect(commits[cherryPickCommitID].branch).toBe('main'); }); @@ -831,8 +831,8 @@ describe('when parsing a gitGraph', function () { 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].tag).toBe([]); + expect(commits[cherryPickCommitID2].tag).toBe([]); expect(commits[cherryPickCommitID].branch).toBe('release'); }); diff --git a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js index 7ccc60cd0..9f8e27a0b 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphRenderer.js +++ b/packages/mermaid/src/diagrams/git/gitGraphRenderer.js @@ -408,59 +408,83 @@ const drawCommits = (svg, commits, modifyGraph) => { } } } - if (commit.tag) { - const rect = gLabels.insert('polygon'); - const hole = gLabels.append('circle'); - const tag = gLabels - .append('text') - // Note that we are delaying setting the x position until we know the width of the text - .attr('y', y - 16) - .attr('class', 'tag-label') - .text(commit.tag); - let tagBbox = tag.node().getBBox(); - tag.attr('x', posWithOffset - tagBbox.width / 2); + if (commit.tags.length > 0) { + let yOffset = 0; + let maxTagBboxWidth = 0; + let maxTagBboxHeight = 0; + const tagElements = []; - const h2 = tagBbox.height / 2; - const ly = y - 19.2; - rect.attr('class', 'tag-label-bkg').attr( - 'points', - ` - ${pos - tagBbox.width / 2 - px / 2},${ly + py} - ${pos - tagBbox.width / 2 - px / 2},${ly - py} - ${posWithOffset - tagBbox.width / 2 - px},${ly - h2 - py} - ${posWithOffset + tagBbox.width / 2 + px},${ly - h2 - py} - ${posWithOffset + tagBbox.width / 2 + px},${ly + h2 + py} - ${posWithOffset - tagBbox.width / 2 - px},${ly + h2 + py}` - ); + for (const tagValue of commit.tags.reverse()) { + const rect = gLabels.insert('polygon'); + const hole = gLabels.append('circle'); + const tag = gLabels + .append('text') + // Note that we are delaying setting the x position until we know the width of the text + .attr('y', y - 16 - yOffset) + .attr('class', 'tag-label') + .text(tagValue); + let tagBbox = tag.node().getBBox(); + maxTagBboxWidth = Math.max(maxTagBboxWidth, tagBbox.width); + maxTagBboxHeight = Math.max(maxTagBboxHeight, tagBbox.height); - hole - .attr('cx', pos - tagBbox.width / 2 + px / 2) - .attr('cy', ly) - .attr('r', 1.5) - .attr('class', 'tag-hole'); + // We don't use the max over here to center the text within the tags + tag.attr('x', posWithOffset - tagBbox.width / 2); + + tagElements.push({ + tag, + hole, + rect, + yOffset, + }); + + yOffset += 20; + } + + for (const { tag, hole, rect, yOffset } of tagElements) { + const h2 = maxTagBboxHeight / 2; + const ly = y - 19.2 - yOffset; + rect.attr('class', 'tag-label-bkg').attr( + 'points', + ` + ${pos - maxTagBboxWidth / 2 - px / 2},${ly + py} + ${pos - maxTagBboxWidth / 2 - px / 2},${ly - py} + ${posWithOffset - maxTagBboxWidth / 2 - px},${ly - h2 - py} + ${posWithOffset + maxTagBboxWidth / 2 + px},${ly - h2 - py} + ${posWithOffset + maxTagBboxWidth / 2 + px},${ly + h2 + py} + ${posWithOffset - maxTagBboxWidth / 2 - px},${ly + h2 + py}` + ); - if (dir === 'TB' || dir === 'BT') { - rect - .attr('class', 'tag-label-bkg') - .attr( - 'points', - ` - ${x},${pos + py} - ${x},${pos - py} - ${x + layoutOffset},${pos - h2 - py} - ${x + layoutOffset + tagBbox.width + px},${pos - h2 - py} - ${x + layoutOffset + tagBbox.width + px},${pos + h2 + py} - ${x + layoutOffset},${pos + h2 + py}` - ) - .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); hole - .attr('cx', x + px / 2) - .attr('cy', pos) - .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); - tag - .attr('x', x + 5) - .attr('y', pos + 3) - .attr('transform', 'translate(14,14) rotate(45, ' + x + ',' + pos + ')'); + .attr('cy', ly) + .attr('cx', pos - maxTagBboxWidth / 2 + px / 2) + .attr('r', 1.5) + .attr('class', 'tag-hole'); + + if (dir === 'TB' || dir === 'BT') { + const yOrigin = pos + yOffset; + + rect + .attr('class', 'tag-label-bkg') + .attr( + 'points', + ` + ${x},${yOrigin + py} + ${x},${yOrigin - py} + ${x + layoutOffset},${yOrigin - h2 - py} + ${x + layoutOffset + maxTagBboxWidth + px},${yOrigin - h2 - py} + ${x + layoutOffset + maxTagBboxWidth + px},${yOrigin + h2 + py} + ${x + layoutOffset},${yOrigin + h2 + py}` + ) + .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); + hole + .attr('cx', x + px / 2) + .attr('cy', yOrigin) + .attr('transform', 'translate(12,12) rotate(45, ' + x + ',' + pos + ')'); + tag + .attr('x', x + 5) + .attr('y', yOrigin + 3) + .attr('transform', 'translate(14,14) rotate(45, ' + x + ',' + pos + ')'); + } } } } diff --git a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison index b4670ca0b..2e5293999 100644 --- a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison +++ b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison @@ -128,19 +128,19 @@ mergeStatement : MERGE ref {yy.merge($2,'','','')} | MERGE ref COMMIT_ID STR {yy.merge($2, $4,'','')} | MERGE ref COMMIT_TYPE commitType {yy.merge($2,'', $4,'')} - | MERGE ref COMMIT_TAG STR {yy.merge($2, '','',$4)} - | MERGE ref COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $6,'', $4)} - | MERGE ref COMMIT_TAG STR COMMIT_TYPE commitType {yy.merge($2, '',$6, $4)} - | MERGE ref COMMIT_TYPE commitType COMMIT_TAG STR {yy.merge($2, '',$4, $6)} + | MERGE ref commitTags {yy.merge($2, '','',$3)} + | MERGE ref commitTags COMMIT_ID STR {yy.merge($2, $5,'', $3)} + | MERGE ref commitTags COMMIT_TYPE commitType {yy.merge($2, '',$5, $3)} + | MERGE ref COMMIT_TYPE commitType commitTags {yy.merge($2, '',$4, $5)} | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $4, $6, '')} - | MERGE ref COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $4, '', $6)} + | MERGE ref COMMIT_ID STR commitTags {yy.merge($2, $4, '', $5)} | MERGE ref COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $6,$4, '')} - | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.merge($2, $4, $6, $8)} - | MERGE ref COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.merge($2, $8, $4, $6)} - | MERGE ref COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.merge($2, $4, $8, $6)} - | MERGE ref COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.merge($2, $6, $4, $8)} - | MERGE ref COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $8, $6, $4)} - | MERGE ref COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $6, $8, $4)} + | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.merge($2, $4, $6, $7)} + | MERGE ref COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.merge($2, $7, $4, $5)} + | MERGE ref COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.merge($2, $4, $7, $5)} + | MERGE ref COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.merge($2, $6, $4, $7)} + | MERGE ref commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $7, $5, $3)} + | MERGE ref commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $5, $7, $3)} ; commitStatement @@ -238,6 +238,10 @@ commitType | REVERSE { $$=yy.commitType.REVERSE;} | HIGHLIGHT { $$=yy.commitType.HIGHLIGHT;} ; +commitTags + : COMMIT_TAG STR {$$=[$2]} + | commitTags COMMIT_TAG STR {$commitTags.push($3); $$=$commitTags;} + ; ref : ID From 74c6fc35a85a1e9181793d2e3a2baf2b62717794 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 12:07:12 -0700 Subject: [PATCH 2/9] fix: tests --- .../mermaid/src/diagrams/git/gitGraphAst.js | 21 +++-- .../src/diagrams/git/gitGraphParserV2.spec.js | 89 +++++++++++++------ .../src/diagrams/git/parser/gitGraph.jison | 2 + 3 files changed, 77 insertions(+), 35 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphAst.js b/packages/mermaid/src/diagrams/git/gitGraphAst.js index ca9bbb010..a882de295 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphAst.js +++ b/packages/mermaid/src/diagrams/git/gitGraphAst.js @@ -216,8 +216,8 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag ' already exists, use different custom Id' ); error.hash = { - text: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join(','), - token: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join(','), + text: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join?.(','), + token: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join?.(','), line: '1', loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 }, expected: [ @@ -228,7 +228,7 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag '_UNIQUE ' + override_type + ' ' + - custom_tags.join(','), + custom_tags.join?.(','), ], }; @@ -336,11 +336,16 @@ export const cherryPick = function (sourceId, targetId, tag, parentCommitId) { parents: [head == null ? null : head.id, sourceCommit.id], branch: curBranch, type: commitType.CHERRY_PICK, - tags: tag ? [tag] : [ - `cherry-pick:${sourceCommit.id}${ - sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : '' - }`, - ], + tags: + typeof tag === 'string' + ? tag + ? [tag] + : [] + : [ + `cherry-pick:${sourceCommit.id}${ + sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : '' + }`, + ], }; head = commit; commits[commit.id] = commit; diff --git a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js index 53e69c620..db4a53492 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js +++ b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js @@ -20,7 +20,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(0); }); @@ -37,7 +37,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(0); }); @@ -55,7 +55,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe('test'); + expect(commits[key].tags).toStrictEqual(['test']); expect(commits[key].type).toBe(0); }); @@ -73,7 +73,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(2); }); @@ -91,7 +91,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(1); }); @@ -109,7 +109,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(0); }); @@ -127,7 +127,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test commit'); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(0); }); @@ -145,7 +145,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test commit'); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe([]); + expect(commits[key].tags).toStrictEqual([]); expect(commits[key].type).toBe(0); }); @@ -163,7 +163,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(0); }); @@ -181,7 +181,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(2); }); @@ -199,7 +199,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).not.toBeNull(); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(2); }); @@ -217,7 +217,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe(''); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(1); }); @@ -235,7 +235,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test msg'); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(1); }); @@ -254,7 +254,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test msg'); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(1); }); @@ -272,7 +272,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test msg'); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(1); }); @@ -290,7 +290,7 @@ describe('when parsing a gitGraph', function () { const key = Object.keys(commits)[0]; expect(commits[key].message).toBe('test msg'); expect(commits[key].id).toBe('1111'); - expect(commits[key].tag).toBe('test tag'); + expect(commits[key].tags).toStrictEqual(['test tag']); expect(commits[key].type).toBe(1); }); @@ -620,7 +620,42 @@ describe('when parsing a gitGraph', function () { expect(commits[commit3].branch).toBe('main'); expect(commits[commit3].parents).toStrictEqual([commits[commit1].id, commits[commit2].id]); - expect(commits[commit3].tag).toBe('merge-tag'); + expect(commits[commit3].tags).toStrictEqual(['merge-tag']); + expect(parser.yy.getBranchesAsObjArray()).toStrictEqual([ + { name: 'main' }, + { name: 'testBranch' }, + ]); + }); + + it('should handle merge with multiple tags', function () { + const str = `gitGraph: + commit + branch testBranch + checkout testBranch + commit + checkout main + merge testBranch tag: "merge-tag1" tag: "merge-tag2" + `; + + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(2); + const commit1 = Object.keys(commits)[0]; + const commit2 = Object.keys(commits)[1]; + const commit3 = Object.keys(commits)[2]; + + expect(commits[commit1].branch).toBe('main'); + expect(commits[commit1].parents).toStrictEqual([]); + + expect(commits[commit2].branch).toBe('testBranch'); + expect(commits[commit2].parents).toStrictEqual([commits[commit1].id]); + + expect(commits[commit3].branch).toBe('main'); + expect(commits[commit3].parents).toStrictEqual([commits[commit1].id, commits[commit2].id]); + expect(commits[commit3].tags).toStrictEqual(['merge-tag1', 'merge-tag2']); expect(parser.yy.getBranchesAsObjArray()).toStrictEqual([ { name: 'main' }, { name: 'testBranch' }, @@ -675,12 +710,12 @@ describe('when parsing a gitGraph', function () { expect(testBranchMerge.branch).toBe('main'); expect(testBranchMerge.parents).toStrictEqual([mainCommit.id, testBranchCommit.id]); - expect(testBranchMerge.tag).toBe('merge-tag'); + expect(testBranchMerge.tags).toStrictEqual(['merge-tag']); expect(testBranchMerge.id).toBe('2-222'); expect(testBranch2Merge.branch).toBe('main'); expect(testBranch2Merge.parents).toStrictEqual([testBranchMerge.id, testBranch2Commit.id]); - expect(testBranch2Merge.tag).toBe('merge-tag2'); + expect(testBranch2Merge.tags).toStrictEqual(['merge-tag2']); expect(testBranch2Merge.id).toBe('4-444'); expect(testBranch2Merge.customType).toBe(2); expect(testBranch2Merge.customId).toBe(true); @@ -709,7 +744,7 @@ describe('when parsing a gitGraph', function () { parser.parse(str); const commits = parser.yy.getCommits(); const cherryPickCommitID = Object.keys(commits)[2]; - expect(commits[cherryPickCommitID].tag).toBe('cherry-pick:A'); + expect(commits[cherryPickCommitID].tags).toStrictEqual(['cherry-pick:A']); expect(commits[cherryPickCommitID].branch).toBe('main'); }); @@ -725,7 +760,7 @@ describe('when parsing a gitGraph', function () { parser.parse(str); const commits = parser.yy.getCommits(); const cherryPickCommitID = Object.keys(commits)[2]; - expect(commits[cherryPickCommitID].tag).toBe('MyTag'); + expect(commits[cherryPickCommitID].tags).toStrictEqual(['MyTag']); expect(commits[cherryPickCommitID].branch).toBe('main'); }); @@ -741,7 +776,7 @@ describe('when parsing a gitGraph', function () { parser.parse(str); const commits = parser.yy.getCommits(); const cherryPickCommitID = Object.keys(commits)[2]; - expect(commits[cherryPickCommitID].tag).toBe([]); + expect(commits[cherryPickCommitID].tags).toStrictEqual([]); expect(commits[cherryPickCommitID].branch).toBe('main'); }); @@ -762,7 +797,7 @@ describe('when parsing a gitGraph', function () { 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].tags).toStrictEqual(['cherry-pick:M|parent:B']); expect(commits[cherryPickCommitID].branch).toBe('release'); }); @@ -783,7 +818,7 @@ describe('when parsing a gitGraph', function () { parser.parse(str); const commits = parser.yy.getCommits(); const cherryPickCommitID = Object.keys(commits)[4]; - expect(commits[cherryPickCommitID].tag).toBe('v1.0'); + expect(commits[cherryPickCommitID].tags).toStrictEqual(['v1.0']); expect(commits[cherryPickCommitID].branch).toBe('release'); }); @@ -806,7 +841,7 @@ describe('when parsing a gitGraph', function () { 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].tags).toStrictEqual(['v2.1:ZERO']); expect(commits[cherryPickCommitID].branch).toBe('release'); }); @@ -831,8 +866,8 @@ describe('when parsing a gitGraph', function () { 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].tags).toStrictEqual([]); + expect(commits[cherryPickCommitID2].tags).toStrictEqual([]); expect(commits[cherryPickCommitID].branch).toBe('release'); }); diff --git a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison index 2e5293999..429b6f8bc 100644 --- a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison +++ b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison @@ -240,7 +240,9 @@ commitType ; commitTags : COMMIT_TAG STR {$$=[$2]} + | COMMIT_TAG EMPTYSTR {$$=['']} | commitTags COMMIT_TAG STR {$commitTags.push($3); $$=$commitTags;} + | commitTags COMMIT_TAG EMPTYSTR {$commitTags.push(''); $$=$commitTags;} ; ref From 05a3806075774ed47f12bfe6df2d75e59c270f8d Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 12:39:18 -0700 Subject: [PATCH 3/9] feat: cherry picks with multiple tags --- .../mermaid/src/diagrams/git/gitGraphAst.js | 37 ++-- .../src/diagrams/git/gitGraphParserV2.spec.js | 16 ++ .../src/diagrams/git/parser/gitGraph.jison | 165 ++++++++---------- 3 files changed, 107 insertions(+), 111 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphAst.js b/packages/mermaid/src/diagrams/git/gitGraphAst.js index a882de295..ecb37053a 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphAst.js +++ b/packages/mermaid/src/diagrams/git/gitGraphAst.js @@ -103,17 +103,17 @@ export const getOptions = function () { return options; }; -export const commit = function (msg, id, type, tag) { - log.debug('Entering commit:', msg, id, type, tag); +export const commit = function (msg, id, type, tags) { + log.debug('Entering commit:', msg, id, type, tags); id = common.sanitizeText(id, getConfig()); msg = common.sanitizeText(msg, getConfig()); - tag = common.sanitizeText(tag, getConfig()); + tags = tags?.map((tag) => common.sanitizeText(tag, getConfig())); const commit = { id: id ? id : seq + '-' + getId(), message: msg, seq: seq++, type: type ? type : commitType.NORMAL, - tags: tag ? [tag] : [], + tags: tags ?? [], parents: head == null ? [] : [head.id], branch: curBranch, }; @@ -216,8 +216,8 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag ' already exists, use different custom Id' ); error.hash = { - text: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join?.(','), - token: 'merge ' + otherBranch + custom_id + override_type + custom_tags.join?.(','), + text: 'merge ' + otherBranch + custom_id + override_type + custom_tags?.join(','), + token: 'merge ' + otherBranch + custom_id + override_type + custom_tags?.join(','), line: '1', loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 }, expected: [ @@ -228,7 +228,7 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag '_UNIQUE ' + override_type + ' ' + - custom_tags.join?.(','), + custom_tags?.join(','), ], }; @@ -262,11 +262,11 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag log.debug('in mergeBranch'); }; -export const cherryPick = function (sourceId, targetId, tag, parentCommitId) { - log.debug('Entering cherryPick:', sourceId, targetId, tag); +export const cherryPick = function (sourceId, targetId, tags, parentCommitId) { + log.debug('Entering cherryPick:', sourceId, targetId, tags); sourceId = common.sanitizeText(sourceId, getConfig()); targetId = common.sanitizeText(targetId, getConfig()); - tag = common.sanitizeText(tag, getConfig()); + tags = tags?.map((tag) => common.sanitizeText(tag, getConfig())); parentCommitId = common.sanitizeText(parentCommitId, getConfig()); if (!sourceId || commits[sourceId] === undefined) { @@ -336,16 +336,13 @@ export const cherryPick = function (sourceId, targetId, tag, parentCommitId) { parents: [head == null ? null : head.id, sourceCommit.id], branch: curBranch, type: commitType.CHERRY_PICK, - tags: - typeof tag === 'string' - ? tag - ? [tag] - : [] - : [ - `cherry-pick:${sourceCommit.id}${ - sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : '' - }`, - ], + tags: tags + ? tags.filter(Boolean) + : [ + `cherry-pick:${sourceCommit.id}${ + sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : '' + }`, + ], }; head = commit; commits[commit.id] = commit; diff --git a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js index db4a53492..8bbe828a8 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js +++ b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js @@ -764,6 +764,22 @@ describe('when parsing a gitGraph', function () { expect(commits[cherryPickCommitID].branch).toBe('main'); }); + it('should support cherry-picking commits with multiple tags', function () { + const str = `gitGraph + commit id: "ZERO" + branch develop + commit id:"A" + checkout main + cherry-pick id:"A" tag:"MyTag" tag:"MyTag2" + `; + + parser.parse(str); + const commits = parser.yy.getCommits(); + const cherryPickCommitID = Object.keys(commits)[2]; + expect(commits[cherryPickCommitID].tags).toStrictEqual(['MyTag', 'MyTag2']); + expect(commits[cherryPickCommitID].branch).toBe('main'); + }); + it('should support cherry-picking commits with no tag', function () { const str = `gitGraph commit id: "ZERO" diff --git a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison index 429b6f8bc..fa2c70586 100644 --- a/packages/mermaid/src/diagrams/git/parser/gitGraph.jison +++ b/packages/mermaid/src/diagrams/git/parser/gitGraph.jison @@ -112,29 +112,24 @@ 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 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($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)} + | CHERRY_PICK COMMIT_ID STR commitTags {yy.cherryPick($3, '', $4)} + | CHERRY_PICK COMMIT_ID STR PARENT_COMMIT STR commitTags {yy.cherryPick($3, '', $6,$5)} + | CHERRY_PICK COMMIT_ID STR commitTags PARENT_COMMIT STR {yy.cherryPick($3, '', $4,$6)} + | CHERRY_PICK commitTags COMMIT_ID STR {yy.cherryPick($4, '', $2)} + | CHERRY_PICK commitTags COMMIT_ID STR PARENT_COMMIT STR {yy.cherryPick($4, '', $2,$6)} ; mergeStatement - : MERGE ref {yy.merge($2,'','','')} - | MERGE ref COMMIT_ID STR {yy.merge($2, $4,'','')} - | MERGE ref COMMIT_TYPE commitType {yy.merge($2,'', $4,'')} + : MERGE ref {yy.merge($2,'','', undefined)} + | MERGE ref COMMIT_ID STR {yy.merge($2, $4,'', undefined)} + | MERGE ref COMMIT_TYPE commitType {yy.merge($2,'', $4, undefined)} | MERGE ref commitTags {yy.merge($2, '','',$3)} | MERGE ref commitTags COMMIT_ID STR {yy.merge($2, $5,'', $3)} | MERGE ref commitTags COMMIT_TYPE commitType {yy.merge($2, '',$5, $3)} | MERGE ref COMMIT_TYPE commitType commitTags {yy.merge($2, '',$4, $5)} - | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $4, $6, '')} + | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType {yy.merge($2, $4, $6, undefined)} | MERGE ref COMMIT_ID STR commitTags {yy.merge($2, $4, '', $5)} - | MERGE ref COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $6,$4, '')} + | MERGE ref COMMIT_TYPE commitType COMMIT_ID STR {yy.merge($2, $6,$4, undefined)} | MERGE ref COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.merge($2, $4, $6, $7)} | MERGE ref COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.merge($2, $7, $4, $5)} | MERGE ref COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.merge($2, $4, $7, $5)} @@ -145,89 +140,77 @@ mergeStatement commitStatement : COMMIT commit_arg {yy.commit($2)} - | COMMIT COMMIT_TAG STR {yy.commit('','',yy.commitType.NORMAL,$3)} - | COMMIT COMMIT_TYPE commitType {yy.commit('','',$3,'')} - | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('','',$5,$3)} - | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('','',$3,$5)} - | COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL,'')} - | COMMIT COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$3,yy.commitType.NORMAL,$5)} - | COMMIT COMMIT_TAG STR COMMIT_ID STR {yy.commit('',$5,yy.commitType.NORMAL,$3)} - | COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5,'')} - | COMMIT COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$5,$3,'')} - | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('',$3,$5,$7)} - | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('',$3,$7,$5)} - | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$5,$3,$7)} - | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.commit('',$7,$3,$5)} - | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$7,$5,$3)} - | COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$5,$7,$3)} - | COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL,'')} - | COMMIT COMMIT_TAG STR COMMIT_MSG STR {yy.commit($5,'',yy.commitType.NORMAL,$3)} - | COMMIT COMMIT_MSG STR COMMIT_TAG STR {yy.commit($3,'',yy.commitType.NORMAL,$5)} - | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($3,'',$5,'')} - | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($5,'',$3,'')} - | COMMIT COMMIT_ID STR COMMIT_MSG STR {yy.commit($5,$3,yy.commitType.NORMAL,'')} - | COMMIT COMMIT_MSG STR COMMIT_ID STR {yy.commit($3,$5,yy.commitType.NORMAL,'')} + | COMMIT commitTags {yy.commit('','',yy.commitType.NORMAL,$2)} + | COMMIT COMMIT_TYPE commitType {yy.commit('','',$3, undefined)} + | COMMIT commitTags COMMIT_TYPE commitType {yy.commit('','',$4,$2)} + | COMMIT COMMIT_TYPE commitType commitTags {yy.commit('','',$3,$4)} + | COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL, undefined)} + | COMMIT COMMIT_ID STR commitTags {yy.commit('',$3,yy.commitType.NORMAL,$4)} + | COMMIT commitTags COMMIT_ID STR {yy.commit('',$4,yy.commitType.NORMAL,$2)} + | COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5, undefined)} + | COMMIT COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$5,$3, undefined)} + | COMMIT COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.commit('',$3,$5,$6)} + | COMMIT COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.commit('',$3,$6,$4)} + | COMMIT COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.commit('',$5,$3,$6)} + | COMMIT COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.commit('',$6,$3,$4)} + | COMMIT commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$6,$4,$2)} + | COMMIT commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$4,$6,$2)} + | COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL, undefined)} + | COMMIT commitTags COMMIT_MSG STR {yy.commit($4,'',yy.commitType.NORMAL,$2)} + | COMMIT COMMIT_MSG STR commitTags {yy.commit($3,'',yy.commitType.NORMAL,$4)} + | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($3,'',$5, undefined)} + | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($5,'',$3, undefined)} + | COMMIT COMMIT_ID STR COMMIT_MSG STR {yy.commit($5,$3,yy.commitType.NORMAL, undefined)} + | COMMIT COMMIT_MSG STR COMMIT_ID STR {yy.commit($3,$5,yy.commitType.NORMAL, undefined)} - | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($3,'',$5,$7)} - | COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($3,'',$7,$5)} - | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR {yy.commit($5,'',$3,$7)} - | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR {yy.commit($7,'',$3,$5)} - | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,'',$5,$3)} - | COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,'',$7,$3)} + | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType commitTags {yy.commit($3,'',$5,$6)} + | COMMIT COMMIT_MSG STR commitTags COMMIT_TYPE commitType {yy.commit($3,'',$6,$4)} + | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR commitTags {yy.commit($5,'',$3,$6)} + | COMMIT COMMIT_TYPE commitType commitTags COMMIT_MSG STR {yy.commit($6,'',$3,$4)} + | COMMIT commitTags COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($6,'',$4,$2)} + | COMMIT commitTags COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($4,'',$6,$2)} - | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$7,$5,'')} - | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$5,$7,'')} - | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,$3,'')} - | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,$3,'')} - | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,$3,$5,'')} - | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,$3,$7,'')} + | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$7,$5, undefined)} + | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$5,$7, undefined)} + | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,$3, undefined)} + | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,$3, undefined)} + | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,$3,$5, undefined)} + | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,$3,$7, undefined)} - | COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR {yy.commit($3,$7,yy.commitType.NORMAL,$5)} - | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR {yy.commit($3,$5,yy.commitType.NORMAL,$7)} - | COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,yy.commitType.NORMAL,$3)} - | COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,yy.commitType.NORMAL,$3)} - | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR {yy.commit($7,$3,yy.commitType.NORMAL,$5)} - | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR {yy.commit($5,$3,yy.commitType.NORMAL,$7)} + | COMMIT COMMIT_MSG STR commitTags COMMIT_ID STR {yy.commit($3,$6,yy.commitType.NORMAL,$4)} + | COMMIT COMMIT_MSG STR COMMIT_ID STR commitTags {yy.commit($3,$5,yy.commitType.NORMAL,$6)} + | COMMIT commitTags COMMIT_MSG STR COMMIT_ID STR {yy.commit($4,$6,yy.commitType.NORMAL,$2)} + | COMMIT commitTags COMMIT_ID STR COMMIT_MSG STR {yy.commit($6,$4,yy.commitType.NORMAL,$2)} + | COMMIT COMMIT_ID STR commitTags COMMIT_MSG STR {yy.commit($6,$3,yy.commitType.NORMAL,$4)} + | COMMIT COMMIT_ID STR COMMIT_MSG STR commitTags {yy.commit($5,$3,yy.commitType.NORMAL,$6)} - | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($3,$5,$7,$9)} - | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($3,$5,$9,$7)} - | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.commit($3,$7,$5,$9)} - | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.commit($3,$9,$5,$7)} - | COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$7,$9,$5)} - | COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$9,$7,$5)} + | COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType commitTags {yy.commit($3,$5,$7,$8)} + | COMMIT COMMIT_MSG STR COMMIT_ID STR commitTags COMMIT_TYPE commitType {yy.commit($3,$5,$8,$6)} + | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR commitTags {yy.commit($3,$7,$5,$8)} + | COMMIT COMMIT_MSG STR COMMIT_TYPE commitType commitTags COMMIT_ID STR {yy.commit($3,$8,$5,$6)} + | COMMIT COMMIT_MSG STR commitTags COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$6,$8,$4)} + | COMMIT COMMIT_MSG STR commitTags COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$8,$6,$4)} - | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($5,$3,$7,$9)} - | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($5,$3,$9,$7)} - | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR {yy.commit($7,$3,$5,$9)} - | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR {yy.commit($9,$3,$5,$7)} - | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($7,$3,$9,$5)} - | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($9,$3,$7,$5)} + | COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType commitTags {yy.commit($5,$3,$7,$8)} + | COMMIT COMMIT_ID STR COMMIT_MSG STR commitTags COMMIT_TYPE commitType {yy.commit($5,$3,$8,$6)} + | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR commitTags {yy.commit($7,$3,$5,$8)} + | COMMIT COMMIT_ID STR COMMIT_TYPE commitType commitTags COMMIT_MSG STR {yy.commit($8,$3,$5,$6)} + | COMMIT COMMIT_ID STR commitTags COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($6,$3,$8,$4)} + | COMMIT COMMIT_ID STR commitTags COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($8,$3,$6,$4)} - | COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($9,$5,$7,$3)} - | COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($7,$5,$9,$3)} - | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($9,$7,$5,$3)} - | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($7,$9,$5,$3)} - | COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($5,$7,$9,$3)} - | COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($5,$9,$7,$3)} + | COMMIT commitTags COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($8,$4,$6,$2)} + | COMMIT commitTags COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($6,$4,$8,$2)} + | COMMIT commitTags COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($8,$6,$4,$2)} + | COMMIT commitTags COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($6,$8,$4,$2)} + | COMMIT commitTags COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($4,$6,$8,$2)} + | COMMIT commitTags COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($4,$8,$6,$2)} - | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR {yy.commit($7,$5,$3,$9)} - | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR {yy.commit($9,$5,$3,$7)} - | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR {yy.commit($7,$9,$3,$5)} - | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR {yy.commit($9,$7,$3,$5)} - | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR {yy.commit($5,$7,$3,$9)} - | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR {yy.commit($5,$9,$3,$7)} - - - // | COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL,'')} - // | COMMIT COMMIT_TYPE commitType {yy.commit('','',$3,'')} - // | COMMIT COMMIT_TAG STR {yy.commit('','',yy.commitType.NORMAL,$3)} - // | COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL,'')} - // | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('','',$5,$3)} - // | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('','',$3,$5)} - // | COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5,'')} - // | COMMIT COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$3,yy.commitType.NORMAL,$5)} - // | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('',$3,$5,$7)} - // | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('',$3,$7,$5)} + | COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR commitTags {yy.commit($7,$5,$3,$8)} + | COMMIT COMMIT_TYPE commitType COMMIT_ID STR commitTags COMMIT_MSG STR {yy.commit($8,$5,$3,$6)} + | COMMIT COMMIT_TYPE commitType commitTags COMMIT_MSG STR COMMIT_ID STR {yy.commit($6,$8,$3,$4)} + | COMMIT COMMIT_TYPE commitType commitTags COMMIT_ID STR COMMIT_MSG STR {yy.commit($8,$6,$3,$4)} + | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR commitTags {yy.commit($5,$7,$3,$8)} + | COMMIT COMMIT_TYPE commitType COMMIT_MSG STR commitTags COMMIT_ID STR {yy.commit($5,$8,$3,$6)} ; commit_arg : /* empty */ {$$ = ""} From 5868a96494f42b3b2651407d9ee4223a9ff47657 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 12:42:19 -0700 Subject: [PATCH 4/9] test: git graph --- .../src/diagrams/git/gitGraphParserV2.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js index 8bbe828a8..fff1926ce 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js +++ b/packages/mermaid/src/diagrams/git/gitGraphParserV2.spec.js @@ -59,6 +59,24 @@ describe('when parsing a gitGraph', function () { expect(commits[key].type).toBe(0); }); + it('should handle a gitGraph commit with multiple commit tags', function () { + const str = `gitGraph: + commit tag:"test" tag:"test2" + `; + + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('main'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + const key = Object.keys(commits)[0]; + expect(commits[key].message).toBe(''); + expect(commits[key].id).not.toBeNull(); + expect(commits[key].tags).toStrictEqual(['test', 'test2']); + expect(commits[key].type).toBe(0); + }); + it('should handle a gitGraph commit with custom commit type HIGHLIGHT only', function () { const str = `gitGraph: commit type: HIGHLIGHT From bfeab9ec0b17d82bd42cfdd8eff6f8a0cfa7e5a2 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 13:20:27 -0700 Subject: [PATCH 5/9] test: e2e left-right --- cypress/integration/rendering/gitGraph.spec.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index 68b63de46..38714de5b 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -1533,4 +1533,22 @@ gitGraph TB: ); }); }); + it('75: should render a gitGraph with multiple tags on a merge commit', () => { + imgSnapshotTest( + `gitGraph + commit id: "ZERO" + branch develop + commit id:"A" + checkout main + commit id:"ONE" + checkout develop + commit id:"B" + checkout main + merge develop id:"Release 1.0" type:HIGHLIGHT tag: "SAML v2.0" tag: "OpenID v1.1" + commit id:"TWO" + checkout develop + commit id:"C"`, + {} + ); + }); }); From acb799cca099c33661c01cfb60e17c7c74ba19b6 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 13:24:17 -0700 Subject: [PATCH 6/9] test: e2e bottom-top --- .../integration/rendering/gitGraph.spec.js | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index 38714de5b..249febd08 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -1532,8 +1532,26 @@ gitGraph TB: {} ); }); + it('75: should render a gitGraph with multiple tags on a merge commit on bottom-to-top orientation', () => { + imgSnapshotTest( + `gitGraph BT: + commit id: "ZERO" + branch develop + commit id:"A" + checkout main + commit id:"ONE" + checkout develop + commit id:"B" + checkout main + merge develop id:"Release 1.0" type:HIGHLIGHT tag: "SAML v2.0" tag: "OpenID v1.1" + commit id:"TWO" + checkout develop + commit id:"C"`, + {} + ); + }); }); - it('75: should render a gitGraph with multiple tags on a merge commit', () => { + it('76: should render a gitGraph with multiple tags on a merge commit on left-to-right orientation', () => { imgSnapshotTest( `gitGraph commit id: "ZERO" From 38a7a47d1142ecfe01947072f19b7cef121063f2 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 13:26:20 -0700 Subject: [PATCH 7/9] chore: push better live editor script alongside --- scripts/editor.bash | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/editor.bash b/scripts/editor.bash index 381012d30..7c7234870 100755 --- a/scripts/editor.bash +++ b/scripts/editor.bash @@ -19,10 +19,9 @@ pnpm build:esbuild pnpm build:types # Clone the Mermaid Live Editor repository -rm -rf mermaid-live-editor -git clone --single-branch https://github.com/mermaid-js/mermaid-live-editor.git - cd mermaid-live-editor +git clean -xdf +rm -rf docs/ # We have to use npm instead of yarn because it causes trouble in netlify # Install dependencies From ab1a2ec41139b02fdb71e5ff8d7c87a70e61abb2 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 16 Jul 2024 18:24:04 -0700 Subject: [PATCH 8/9] fix: clone if editor doesnt exist in script --- scripts/editor.bash | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/editor.bash b/scripts/editor.bash index 7c7234870..d04246cc7 100755 --- a/scripts/editor.bash +++ b/scripts/editor.bash @@ -19,6 +19,9 @@ pnpm build:esbuild pnpm build:types # Clone the Mermaid Live Editor repository +if [ ! -d "mermaid-live-editor" ]; then + git clone --single-branch https://github.com/mermaid-js/mermaid-live-editor.git +fi cd mermaid-live-editor git clean -xdf rm -rf docs/ From eb714eb71a48b846827e3e1f333d7a06c5a75ea6 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 18 Jul 2024 10:07:06 +0530 Subject: [PATCH 9/9] chore: Cleanup getConfig() --- .../mermaid/src/diagrams/git/gitGraphAst.js | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/packages/mermaid/src/diagrams/git/gitGraphAst.js b/packages/mermaid/src/diagrams/git/gitGraphAst.js index df07f20bb..cebc4fc3e 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphAst.js +++ b/packages/mermaid/src/diagrams/git/gitGraphAst.js @@ -12,8 +12,7 @@ import { getDiagramTitle, } from '../common/commonDb.js'; -let mainBranchName = getConfig().gitGraph.mainBranchName; -let mainBranchOrder = getConfig().gitGraph.mainBranchOrder; +let { mainBranchName, mainBranchOrder } = getConfig().gitGraph; let commits = new Map(); let head = null; let branchesConfig = new Map(); @@ -105,9 +104,10 @@ export const getOptions = function () { export const commit = function (msg, id, type, tags) { log.debug('Entering commit:', msg, id, type, tags); - id = common.sanitizeText(id, getConfig()); - msg = common.sanitizeText(msg, getConfig()); - tags = tags?.map((tag) => common.sanitizeText(tag, getConfig())); + const config = getConfig(); + id = common.sanitizeText(id, config); + msg = common.sanitizeText(msg, config); + tags = tags?.map((tag) => common.sanitizeText(tag, config)); const commit = { id: id ? id : seq + '-' + getId(), message: msg, @@ -148,8 +148,9 @@ export const branch = function (name, order) { }; export const merge = function (otherBranch, custom_id, override_type, custom_tags) { - otherBranch = common.sanitizeText(otherBranch, getConfig()); - custom_id = common.sanitizeText(custom_id, getConfig()); + const config = getConfig(); + otherBranch = common.sanitizeText(otherBranch, config); + custom_id = common.sanitizeText(custom_id, config); const currentCommit = commits.get(branches.get(curBranch)); const otherCommit = commits.get(branches.get(otherBranch)); @@ -221,14 +222,7 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag line: '1', loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 }, expected: [ - 'merge ' + - otherBranch + - ' ' + - custom_id + - '_UNIQUE ' + - override_type + - ' ' + - custom_tags?.join(','), + `merge ${otherBranch} ${custom_id}_UNIQUE ${override_type} ${custom_tags?.join(',')}`, ], }; @@ -264,10 +258,11 @@ export const merge = function (otherBranch, custom_id, override_type, custom_tag export const cherryPick = function (sourceId, targetId, tags, parentCommitId) { log.debug('Entering cherryPick:', sourceId, targetId, tags); - sourceId = common.sanitizeText(sourceId, getConfig()); - targetId = common.sanitizeText(targetId, getConfig()); - tags = tags?.map((tag) => common.sanitizeText(tag, getConfig())); - parentCommitId = common.sanitizeText(parentCommitId, getConfig()); + const config = getConfig(); + sourceId = common.sanitizeText(sourceId, config); + targetId = common.sanitizeText(targetId, config); + tags = tags?.map((tag) => common.sanitizeText(tag, config)); + parentCommitId = common.sanitizeText(parentCommitId, config); if (!sourceId || !commits.has(sourceId)) { let error = new Error( @@ -365,8 +360,6 @@ export const checkout = function (branch) { expected: ['"branch ' + branch + '"'], }; throw error; - //branches[branch] = head != null ? head.id : null; - //log.debug('in createBranch'); } else { curBranch = branch; const id = branches.get(curBranch); @@ -453,13 +446,12 @@ export const prettyPrint = function () { export const clear = function () { commits = new Map(); head = null; - let mainBranch = getConfig().gitGraph.mainBranchName; - let mainBranchOrder = getConfig().gitGraph.mainBranchOrder; + const { mainBranchName, mainBranchOrder } = getConfig().gitGraph; branches = new Map(); - branches.set(mainBranch, null); + branches.set(mainBranchName, null); branchesConfig = new Map(); - branchesConfig.set(mainBranch, { name: mainBranch, order: mainBranchOrder }); - curBranch = mainBranch; + branchesConfig.set(mainBranchName, { name: mainBranchName, order: mainBranchOrder }); + curBranch = mainBranchName; seq = 0; commonClear(); };