From a2e3f3d9006d731800e9742688d4466319aa1a2c Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:56:54 -0700 Subject: [PATCH] #931 Reformatting code for gitGraph --- src/diagrams/git/gitGraphAst.js | 292 ++++++++++--------- src/diagrams/git/gitGraphParser.spec.js | 310 ++++++++++---------- src/diagrams/git/gitGraphRenderer.js | 363 ++++++++++++++---------- 3 files changed, 510 insertions(+), 455 deletions(-) diff --git a/src/diagrams/git/gitGraphAst.js b/src/diagrams/git/gitGraphAst.js index f7338c5ed..85e8f7905 100644 --- a/src/diagrams/git/gitGraphAst.js +++ b/src/diagrams/git/gitGraphAst.js @@ -1,98 +1,100 @@ -import _ from 'lodash' +import _ from 'lodash'; -import { logger } from '../../logger' +import { logger } from '../../logger'; -let commits = {} -let head = null -let branches = { 'master': head } -let curBranch = 'master' -let direction = 'LR' -let seq = 0 +let commits = {}; +let head = null; +let branches = { master: head }; +let curBranch = 'master'; +let direction = 'LR'; +let seq = 0; -function getRandomInt (min, max) { - return Math.floor(Math.random() * (max - min)) + min +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min)) + min; } -function getId () { - const pool = '0123456789abcdef' - let id = '' +function getId() { + const pool = '0123456789abcdef'; + let id = ''; for (let i = 0; i < 7; i++) { - id += pool[getRandomInt(0, 16)] + id += pool[getRandomInt(0, 16)]; } - return id + return id; } -function isfastforwardable (currentCommit, otherCommit) { - logger.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id) +function isfastforwardable(currentCommit, otherCommit) { + logger.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id); while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit) { // only if other branch has more commits - if (otherCommit.parent == null) break + if (otherCommit.parent == null) break; if (Array.isArray(otherCommit.parent)) { - logger.debug('In merge commit:', otherCommit.parent) - return isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) || + logger.debug('In merge commit:', otherCommit.parent); + return ( + isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) || isfastforwardable(currentCommit, commits[otherCommit.parent[1]]) + ); } else { - otherCommit = commits[otherCommit.parent] + otherCommit = commits[otherCommit.parent]; } } - logger.debug(currentCommit.id, otherCommit.id) - return currentCommit.id === otherCommit.id + logger.debug(currentCommit.id, otherCommit.id); + return currentCommit.id === otherCommit.id; } -function isReachableFrom (currentCommit, otherCommit) { - const currentSeq = currentCommit.seq - const otherSeq = otherCommit.seq - if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit) - return false +function isReachableFrom(currentCommit, otherCommit) { + const currentSeq = currentCommit.seq; + const otherSeq = otherCommit.seq; + if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit); + return false; } -export const setDirection = function (dir) { - direction = dir -} -let options = {} -export const setOptions = function (rawOptString) { - logger.debug('options str', rawOptString) - rawOptString = rawOptString && rawOptString.trim() - rawOptString = rawOptString || '{}' +export const setDirection = function(dir) { + direction = dir; +}; +let options = {}; +export const setOptions = function(rawOptString) { + logger.debug('options str', rawOptString); + rawOptString = rawOptString && rawOptString.trim(); + rawOptString = rawOptString || '{}'; try { - options = JSON.parse(rawOptString) + options = JSON.parse(rawOptString); } catch (e) { - logger.error('error while parsing gitGraph options', e.message) + logger.error('error while parsing gitGraph options', e.message); } -} +}; -export const getOptions = function () { - return options -} +export const getOptions = function() { + return options; +}; -export const commit = function (msg) { +export const commit = function(msg) { const commit = { id: getId(), message: msg, seq: seq++, parent: head == null ? null : head.id - } - head = commit - commits[commit.id] = commit - branches[curBranch] = commit.id - logger.debug('in pushCommit ' + commit.id) -} + }; + head = commit; + commits[commit.id] = commit; + branches[curBranch] = commit.id; + logger.debug('in pushCommit ' + commit.id); +}; -export const branch = function (name) { - branches[name] = head != null ? head.id : null - logger.debug('in createBranch') -} +export const branch = function(name) { + branches[name] = head != null ? head.id : null; + logger.debug('in createBranch'); +}; -export const merge = function (otherBranch) { - const currentCommit = commits[branches[curBranch]] - const otherCommit = commits[branches[otherBranch]] +export const merge = function(otherBranch) { + const currentCommit = commits[branches[curBranch]]; + const otherCommit = commits[branches[otherBranch]]; if (isReachableFrom(currentCommit, otherCommit)) { - logger.debug('Already merged') - return + logger.debug('Already merged'); + return; } if (isfastforwardable(currentCommit, otherCommit)) { - branches[curBranch] = branches[otherBranch] - head = commits[branches[curBranch]] + branches[curBranch] = branches[otherBranch]; + head = commits[branches[curBranch]]; } else { // create merge commit const commit = { @@ -100,113 +102,125 @@ export const merge = function (otherBranch) { message: 'merged branch ' + otherBranch + ' into ' + curBranch, seq: seq++, parent: [head == null ? null : head.id, branches[otherBranch]] - } - head = commit - commits[commit.id] = commit - branches[curBranch] = commit.id + }; + head = commit; + commits[commit.id] = commit; + branches[curBranch] = commit.id; } - logger.debug(branches) - logger.debug('in mergeBranch') -} + logger.debug(branches); + logger.debug('in mergeBranch'); +}; -export const checkout = function (branch) { - logger.debug('in checkout') - curBranch = branch - const id = branches[curBranch] - head = commits[id] -} +export const checkout = function(branch) { + logger.debug('in checkout'); + curBranch = branch; + const id = branches[curBranch]; + head = commits[id]; +}; -export const reset = function (commitRef) { - logger.debug('in reset', commitRef) - const ref = commitRef.split(':')[0] - let parentCount = parseInt(commitRef.split(':')[1]) - let commit = ref === 'HEAD' ? head : commits[branches[ref]] - logger.debug(commit, parentCount) +export const reset = function(commitRef) { + logger.debug('in reset', commitRef); + const ref = commitRef.split(':')[0]; + let parentCount = parseInt(commitRef.split(':')[1]); + let commit = ref === 'HEAD' ? head : commits[branches[ref]]; + logger.debug(commit, parentCount); while (parentCount > 0) { - commit = commits[commit.parent] - parentCount-- + commit = commits[commit.parent]; + parentCount--; if (!commit) { - const err = 'Critical error - unique parent commit not found during reset' - logger.error(err) - throw err + const err = 'Critical error - unique parent commit not found during reset'; + logger.error(err); + throw err; } } - head = commit - branches[curBranch] = commit.id -} + head = commit; + branches[curBranch] = commit.id; +}; -function upsert (arr, key, newval) { - const index = arr.indexOf(key) +function upsert(arr, key, newval) { + const index = arr.indexOf(key); if (index === -1) { - arr.push(newval) + arr.push(newval); } else { - arr.splice(index, 1, newval) + arr.splice(index, 1, newval); } } -function prettyPrintCommitHistory (commitArr) { - const commit = _.maxBy(commitArr, 'seq') - let line = '' - commitArr.forEach(function (c) { +function prettyPrintCommitHistory(commitArr) { + const commit = _.maxBy(commitArr, 'seq'); + let line = ''; + commitArr.forEach(function(c) { if (c === commit) { - line += '\t*' + line += '\t*'; } else { - line += '\t|' + line += '\t|'; } - }) - const label = [line, commit.id, commit.seq] + }); + const label = [line, commit.id, commit.seq]; for (let branch in branches) { - if (branches[branch] === commit.id) label.push(branch) + if (branches[branch] === commit.id) label.push(branch); } - logger.debug(label.join(' ')) + logger.debug(label.join(' ')); if (Array.isArray(commit.parent)) { - const newCommit = commits[commit.parent[0]] - upsert(commitArr, commit, newCommit) - commitArr.push(commits[commit.parent[1]]) + const newCommit = commits[commit.parent[0]]; + upsert(commitArr, commit, newCommit); + commitArr.push(commits[commit.parent[1]]); } else if (commit.parent == null) { - return + return; } else { - const nextCommit = commits[commit.parent] - upsert(commitArr, commit, nextCommit) + const nextCommit = commits[commit.parent]; + upsert(commitArr, commit, nextCommit); } - commitArr = _.uniqBy(commitArr, 'id') - prettyPrintCommitHistory(commitArr) + commitArr = _.uniqBy(commitArr, 'id'); + prettyPrintCommitHistory(commitArr); } -export const prettyPrint = function () { - logger.debug(commits) - const node = getCommitsArray()[0] - prettyPrintCommitHistory([node]) -} +export const prettyPrint = function() { + logger.debug(commits); + const node = getCommitsArray()[0]; + prettyPrintCommitHistory([node]); +}; -export const clear = function () { - commits = {} - head = null - branches = { 'master': head } - curBranch = 'master' - seq = 0 -} +export const clear = function() { + commits = {}; + head = null; + branches = { master: head }; + curBranch = 'master'; + seq = 0; +}; -export const getBranchesAsObjArray = function () { - const branchArr = [] +export const getBranchesAsObjArray = function() { + const branchArr = []; for (let branch in branches) { - branchArr.push({ name: branch, commit: commits[branches[branch]] }) + branchArr.push({ name: branch, commit: commits[branches[branch]] }); } - return branchArr -} + return branchArr; +}; -export const getBranches = function () { return branches } -export const getCommits = function () { return commits } -export const getCommitsArray = function () { - const commitArr = Object.keys(commits).map(function (key) { - return commits[key] - }) - commitArr.forEach(function (o) { logger.debug(o.id) }) - return _.orderBy(commitArr, ['seq'], ['desc']) -} -export const getCurrentBranch = function () { return curBranch } -export const getDirection = function () { return direction } -export const getHead = function () { return head } +export const getBranches = function() { + return branches; +}; +export const getCommits = function() { + return commits; +}; +export const getCommitsArray = function() { + const commitArr = Object.keys(commits).map(function(key) { + return commits[key]; + }); + commitArr.forEach(function(o) { + logger.debug(o.id); + }); + return _.orderBy(commitArr, ['seq'], ['desc']); +}; +export const getCurrentBranch = function() { + return curBranch; +}; +export const getDirection = function() { + return direction; +}; +export const getHead = function() { + return head; +}; export default { setDirection, @@ -226,4 +240,4 @@ export default { getCurrentBranch, getDirection, getHead -} +}; diff --git a/src/diagrams/git/gitGraphParser.spec.js b/src/diagrams/git/gitGraphParser.spec.js index aba2812d9..6afd7f876 100644 --- a/src/diagrams/git/gitGraphParser.spec.js +++ b/src/diagrams/git/gitGraphParser.spec.js @@ -1,201 +1,186 @@ /* eslint-env jasmine */ -import gitGraphAst from './gitGraphAst' -import { parser } from './parser/gitGraph' +import gitGraphAst from './gitGraphAst'; +import { parser } from './parser/gitGraph'; -describe('when parsing a gitGraph', function () { - beforeEach(function () { - parser.yy = gitGraphAst - parser.yy.clear() - }) - it('should handle a gitGraph defintion', function () { - const str = 'gitGraph:\n' + - 'commit\n' +describe('when parsing a gitGraph', function() { + beforeEach(function() { + parser.yy = gitGraphAst; + parser.yy.clear(); + }); + it('should handle a gitGraph defintion', function() { + const str = 'gitGraph:\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle a gitGraph defintion with empty options', function () { - const str = 'gitGraph:\n' + - 'options\n' + - 'end\n' + - 'commit\n' + it('should handle a gitGraph defintion with empty options', function() { + const str = 'gitGraph:\n' + 'options\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(parser.yy.getOptions()).toEqual({}) - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(parser.yy.getOptions()).toEqual({}); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle a gitGraph defintion with valid options', function () { - const str = 'gitGraph:\n' + - 'options\n' + - '{"key": "value"}\n' + - 'end\n' + - 'commit\n' + it('should handle a gitGraph defintion with valid options', function() { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"}\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() - expect(parser.yy.getOptions()['key']).toBe('value') - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(parser.yy.getOptions()['key']).toBe('value'); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should not fail on a gitGraph with malformed json', function () { - const str = 'gitGraph:\n' + - 'options\n' + - '{"key": "value"\n' + - 'end\n' + - 'commit\n' + it('should not fail on a gitGraph with malformed json', function() { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle set direction', function () { - const str = 'gitGraph BT:\n' + - 'commit\n' + it('should handle set direction', function() { + const str = 'gitGraph BT:\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('BT') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('BT'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should checkout a branch', function () { - const str = 'gitGraph:\n' + - 'branch new\n' + - 'checkout new\n' + it('should checkout a branch', function() { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(0) - expect(parser.yy.getCurrentBranch()).toBe('new') - }) + expect(Object.keys(commits).length).toBe(0); + expect(parser.yy.getCurrentBranch()).toBe('new'); + }); - it('should add commits to checked out branch', function () { - const str = 'gitGraph:\n' + - 'branch new\n' + - 'checkout new\n' + - 'commit\n' + - 'commit\n' + it('should add commits to checked out branch', function() { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(2) - expect(parser.yy.getCurrentBranch()).toBe('new') - const branchCommit = parser.yy.getBranches()['new'] - expect(branchCommit).not.toBeNull() - expect(commits[branchCommit].parent).not.toBeNull() - }) - it('should handle commit with args', function () { - const str = 'gitGraph:\n' + - 'commit "a commit"\n' + expect(Object.keys(commits).length).toBe(2); + expect(parser.yy.getCurrentBranch()).toBe('new'); + const branchCommit = parser.yy.getBranches()['new']; + expect(branchCommit).not.toBeNull(); + expect(commits[branchCommit].parent).not.toBeNull(); + }); + it('should handle commit with args', function() { + const str = 'gitGraph:\n' + 'commit "a commit"\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - const key = Object.keys(commits)[0] - expect(commits[key].message).toBe('a commit') - expect(parser.yy.getCurrentBranch()).toBe('master') - }) + expect(Object.keys(commits).length).toBe(1); + const key = Object.keys(commits)[0]; + expect(commits[key].message).toBe('a commit'); + expect(parser.yy.getCurrentBranch()).toBe('master'); + }); - it('it should reset a branch', function () { - const str = 'gitGraph:\n' + + it('it should reset a branch', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + - 'reset master\n' + 'reset master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('reset can take an argument', function () { - const str = 'gitGraph:\n' + + it('reset can take an argument', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + - 'reset master^\n' + 'reset master^\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - const master = commits[parser.yy.getBranches()['master']] - expect(parser.yy.getHead().id).toEqual(master.parent) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + const master = commits[parser.yy.getBranches()['master']]; + expect(parser.yy.getHead().id).toEqual(master.parent); + }); - it('it should handle fast forwardable merges', function () { - const str = 'gitGraph:\n' + + it('it should handle fast forwardable merges', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + 'commit\n' + 'checkout master\n' + - 'merge newbranch\n' + 'merge newbranch\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('it should handle cases when merge is a noop', function () { - const str = 'gitGraph:\n' + + it('it should handle cases when merge is a noop', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + 'commit\n' + - 'merge master\n' + 'merge master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('it should handle merge with 2 parents', function () { - const str = 'gitGraph:\n' + + it('it should handle merge with 2 parents', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + @@ -203,19 +188,20 @@ describe('when parsing a gitGraph', function () { 'commit\n' + 'checkout master\n' + 'commit\n' + - 'merge newbranch\n' + 'merge newbranch\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(5) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(5); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); + }); - it('it should handle ff merge when history walk has two parents (merge commit)', function () { - const str = 'gitGraph:\n' + + it('it should handle ff merge when history walk has two parents (merge commit)', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + @@ -226,16 +212,16 @@ describe('when parsing a gitGraph', function () { 'merge newbranch\n' + 'commit\n' + 'checkout newbranch\n' + - 'merge master\n' + 'merge master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(6) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(6); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); - parser.yy.prettyPrint() - }) -}) + parser.yy.prettyPrint(); + }); +}); diff --git a/src/diagrams/git/gitGraphRenderer.js b/src/diagrams/git/gitGraphRenderer.js index 00f56ed1a..9a66141a0 100644 --- a/src/diagrams/git/gitGraphRenderer.js +++ b/src/diagrams/git/gitGraphRenderer.js @@ -1,13 +1,13 @@ -import * as d3 from 'd3' -import _ from 'lodash' +import * as d3 from 'd3'; +import _ from 'lodash'; -import db from './gitGraphAst' -import gitGraphParser from './parser/gitGraph' -import { logger } from '../../logger' -import { interpolateToCurve } from '../../utils' +import db from './gitGraphAst'; +import gitGraphParser from './parser/gitGraph'; +import { logger } from '../../logger'; +import { interpolateToCurve } from '../../utils'; -let allCommitsDict = {} -let branchNum +let allCommitsDict = {}; +let branchNum; let config = { nodeSpacing: 150, nodeFillColor: 'yellow', @@ -25,13 +25,13 @@ let config = { x: -25, y: 0 } -} -let apiConfig = {} -export const setConf = function (c) { - apiConfig = c -} +}; +let apiConfig = {}; +export const setConf = function(c) { + apiConfig = c; +}; -function svgCreateDefs (svg) { +function svgCreateDefs(svg) { svg .append('defs') .append('g') @@ -39,8 +39,9 @@ function svgCreateDefs (svg) { .append('circle') .attr('r', config.nodeRadius) .attr('cx', 0) - .attr('cy', 0) - svg.select('#def-commit') + .attr('cy', 0); + svg + .select('#def-commit') .append('foreignObject') .attr('width', config.nodeLabel.width) .attr('height', config.nodeLabel.height) @@ -49,239 +50,293 @@ function svgCreateDefs (svg) { .attr('class', 'node-label') .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') .append('p') - .html('') + .html(''); } -function svgDrawLine (svg, points, colorIdx, interpolate) { - const curve = interpolateToCurve(interpolate, d3.curveBasis) - const color = config.branchColors[colorIdx % config.branchColors.length] - const lineGen = d3.line() - .x(function (d) { - return Math.round(d.x) +function svgDrawLine(svg, points, colorIdx, interpolate) { + const curve = interpolateToCurve(interpolate, d3.curveBasis); + const color = config.branchColors[colorIdx % config.branchColors.length]; + const lineGen = d3 + .line() + .x(function(d) { + return Math.round(d.x); }) - .y(function (d) { - return Math.round(d.y) + .y(function(d) { + return Math.round(d.y); }) - .curve(curve) + .curve(curve); svg .append('svg:path') .attr('d', lineGen(points)) .style('stroke', color) .style('stroke-width', config.lineStrokeWidth) - .style('fill', 'none') + .style('fill', 'none'); } // Pass in the element and its pre-transform coords -function getElementCoords (element, coords) { - coords = coords || element.node().getBBox() - const ctm = element.node().getCTM() - const xn = ctm.e + coords.x * ctm.a - const yn = ctm.f + coords.y * ctm.d +function getElementCoords(element, coords) { + coords = coords || element.node().getBBox(); + const ctm = element.node().getCTM(); + const xn = ctm.e + coords.x * ctm.a; + const yn = ctm.f + coords.y * ctm.d; return { left: xn, top: yn, width: coords.width, height: coords.height - } + }; } -function svgDrawLineForCommits (svg, fromId, toId, direction, color) { - logger.debug('svgDrawLineForCommits: ', fromId, toId) - const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle')) - const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle')) +function svgDrawLineForCommits(svg, fromId, toId, direction, color) { + logger.debug('svgDrawLineForCommits: ', fromId, toId); + const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle')); + const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle')); switch (direction) { case 'LR': // (toBbox) // +-------- // + (fromBbox) if (fromBbox.left - toBbox.left > config.nodeSpacing) { - const lineStart = { x: fromBbox.left - config.nodeSpacing, y: toBbox.top + toBbox.height / 2 } - const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 } - svgDrawLine(svg, [lineStart, lineEnd], color, 'linear') - svgDrawLine(svg, [ - { x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 }, - { x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 }, - { x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y }, - lineStart], color) + const lineStart = { + x: fromBbox.left - config.nodeSpacing, + y: toBbox.top + toBbox.height / 2 + }; + const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 }; + svgDrawLine(svg, [lineStart, lineEnd], color, 'linear'); + svgDrawLine( + svg, + [ + { x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 }, + { x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 }, + { x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y }, + lineStart + ], + color + ); } else { - svgDrawLine(svg, [{ - 'x': fromBbox.left, - 'y': fromBbox.top + fromBbox.height / 2 - }, { - 'x': fromBbox.left - config.nodeSpacing / 2, - 'y': fromBbox.top + fromBbox.height / 2 - }, { - 'x': fromBbox.left - config.nodeSpacing / 2, - 'y': toBbox.top + toBbox.height / 2 - }, { - 'x': toBbox.left + toBbox.width, - 'y': toBbox.top + toBbox.height / 2 - }], color) + svgDrawLine( + svg, + [ + { + x: fromBbox.left, + y: fromBbox.top + fromBbox.height / 2 + }, + { + x: fromBbox.left - config.nodeSpacing / 2, + y: fromBbox.top + fromBbox.height / 2 + }, + { + x: fromBbox.left - config.nodeSpacing / 2, + y: toBbox.top + toBbox.height / 2 + }, + { + x: toBbox.left + toBbox.width, + y: toBbox.top + toBbox.height / 2 + } + ], + color + ); } - break + break; case 'BT': // + (fromBbox) // | // | // + (toBbox) if (toBbox.top - fromBbox.top > config.nodeSpacing) { - const lineStart = { x: toBbox.left + toBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing } - const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top } - svgDrawLine(svg, [lineStart, lineEnd], color, 'linear') - svgDrawLine(svg, [ - { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height }, - { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2 }, - { x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 }, - lineStart], color) + const lineStart = { + x: toBbox.left + toBbox.width / 2, + y: fromBbox.top + fromBbox.height + config.nodeSpacing + }; + const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top }; + svgDrawLine(svg, [lineStart, lineEnd], color, 'linear'); + svgDrawLine( + svg, + [ + { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height }, + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2 + }, + { x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 }, + lineStart + ], + color + ); } else { - svgDrawLine(svg, [{ - 'x': fromBbox.left + fromBbox.width / 2, - 'y': fromBbox.top + fromBbox.height - }, { - 'x': fromBbox.left + fromBbox.width / 2, - 'y': fromBbox.top + config.nodeSpacing / 2 - }, { - 'x': toBbox.left + toBbox.width / 2, - 'y': toBbox.top - config.nodeSpacing / 2 - }, { - 'x': toBbox.left + toBbox.width / 2, - 'y': toBbox.top - }], color) + svgDrawLine( + svg, + [ + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + fromBbox.height + }, + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + config.nodeSpacing / 2 + }, + { + x: toBbox.left + toBbox.width / 2, + y: toBbox.top - config.nodeSpacing / 2 + }, + { + x: toBbox.left + toBbox.width / 2, + y: toBbox.top + } + ], + color + ); } - break + break; } } -function cloneNode (svg, selector) { - return svg.select(selector).node().cloneNode(true) +function cloneNode(svg, selector) { + return svg + .select(selector) + .node() + .cloneNode(true); } -function renderCommitHistory (svg, commitid, branches, direction) { - let commit - const numCommits = Object.keys(allCommitsDict).length +function renderCommitHistory(svg, commitid, branches, direction) { + let commit; + const numCommits = Object.keys(allCommitsDict).length; if (typeof commitid === 'string') { do { - commit = allCommitsDict[commitid] - logger.debug('in renderCommitHistory', commit.id, commit.seq) + commit = allCommitsDict[commitid]; + logger.debug('in renderCommitHistory', commit.id, commit.seq); if (svg.select('#node-' + commitid).size() > 0) { - return + return; } svg - .append(function () { - return cloneNode(svg, '#def-commit') + .append(function() { + return cloneNode(svg, '#def-commit'); }) .attr('class', 'commit') - .attr('id', function () { - return 'node-' + commit.id + .attr('id', function() { + return 'node-' + commit.id; }) - .attr('transform', function () { + .attr('transform', function() { switch (direction) { case 'LR': - return 'translate(' + (commit.seq * config.nodeSpacing + config.leftMargin) + ', ' + - (branchNum * config.branchOffset) + ')' + return ( + 'translate(' + + (commit.seq * config.nodeSpacing + config.leftMargin) + + ', ' + + branchNum * config.branchOffset + + ')' + ); case 'BT': - return 'translate(' + (branchNum * config.branchOffset + config.leftMargin) + ', ' + - ((numCommits - commit.seq) * config.nodeSpacing) + ')' + return ( + 'translate(' + + (branchNum * config.branchOffset + config.leftMargin) + + ', ' + + (numCommits - commit.seq) * config.nodeSpacing + + ')' + ); } }) .attr('fill', config.nodeFillColor) .attr('stroke', config.nodeStrokeColor) - .attr('stroke-width', config.nodeStrokeWidth) + .attr('stroke-width', config.nodeStrokeWidth); - let branch + let branch; for (let branchName in branches) { if (branches[branchName].commit === commit) { - branch = branches[branchName] - break + branch = branches[branchName]; + break; } } if (branch) { - logger.debug('found branch ', branch.name) - svg.select('#node-' + commit.id + ' p') + logger.debug('found branch ', branch.name); + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'branch-label') - .text(branch.name + ', ') + .text(branch.name + ', '); } - svg.select('#node-' + commit.id + ' p') + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'commit-id') - .text(commit.id) + .text(commit.id); if (commit.message !== '' && direction === 'BT') { - svg.select('#node-' + commit.id + ' p') + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'commit-msg') - .text(', ' + commit.message) + .text(', ' + commit.message); } - commitid = commit.parent - } while (commitid && allCommitsDict[commitid]) + commitid = commit.parent; + } while (commitid && allCommitsDict[commitid]); } if (Array.isArray(commitid)) { - logger.debug('found merge commmit', commitid) - renderCommitHistory(svg, commitid[0], branches, direction) - branchNum++ - renderCommitHistory(svg, commitid[1], branches, direction) - branchNum-- + logger.debug('found merge commmit', commitid); + renderCommitHistory(svg, commitid[0], branches, direction); + branchNum++; + renderCommitHistory(svg, commitid[1], branches, direction); + branchNum--; } } -function renderLines (svg, commit, direction, branchColor) { - branchColor = branchColor || 0 +function renderLines(svg, commit, direction, branchColor) { + branchColor = branchColor || 0; while (commit.seq > 0 && !commit.lineDrawn) { if (typeof commit.parent === 'string') { - svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor) - commit.lineDrawn = true - commit = allCommitsDict[commit.parent] + svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor); + commit.lineDrawn = true; + commit = allCommitsDict[commit.parent]; } else if (Array.isArray(commit.parent)) { - svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor) - svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1) - renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1) - commit.lineDrawn = true - commit = allCommitsDict[commit.parent[0]] + svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor); + svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1); + renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1); + commit.lineDrawn = true; + commit = allCommitsDict[commit.parent[0]]; } } } -export const draw = function (txt, id, ver) { +export const draw = function(txt, id, ver) { try { - const parser = gitGraphParser.parser - parser.yy = db + const parser = gitGraphParser.parser; + parser.yy = db; - logger.debug('in gitgraph renderer', txt, id, ver) + logger.debug('in gitgraph renderer', txt, id, ver); // Parse the graph definition - parser.parse(txt + '\n') + parser.parse(txt + '\n'); - config = _.assign(config, apiConfig, db.getOptions()) - logger.debug('effective options', config) - const direction = db.getDirection() - allCommitsDict = db.getCommits() - const branches = db.getBranchesAsObjArray() + config = _.assign(config, apiConfig, db.getOptions()); + logger.debug('effective options', config); + const direction = db.getDirection(); + allCommitsDict = db.getCommits(); + const branches = db.getBranchesAsObjArray(); if (direction === 'BT') { - config.nodeLabel.x = branches.length * config.branchOffset - config.nodeLabel.width = '100%' - config.nodeLabel.y = -1 * 2 * config.nodeRadius + config.nodeLabel.x = branches.length * config.branchOffset; + config.nodeLabel.width = '100%'; + config.nodeLabel.y = -1 * 2 * config.nodeRadius; } - const svg = d3.select(`[id="${id}"]`) - svgCreateDefs(svg) - branchNum = 1 + const svg = d3.select(`[id="${id}"]`); + svgCreateDefs(svg); + branchNum = 1; for (let branch in branches) { - const v = branches[branch] - renderCommitHistory(svg, v.commit.id, branches, direction) - renderLines(svg, v.commit, direction) - branchNum++ + const v = branches[branch]; + renderCommitHistory(svg, v.commit.id, branches, direction); + renderLines(svg, v.commit, direction); + branchNum++; } - svg.attr('height', function () { - if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing - return (branches.length + 1) * config.branchOffset - }) + svg.attr('height', function() { + if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing; + return (branches.length + 1) * config.branchOffset; + }); } catch (e) { - logger.error('Error while rendering gitgraph') - logger.error(e.message) + logger.error('Error while rendering gitgraph'); + logger.error(e.message); } -} +}; export default { setConf, draw -} +};