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