From 123fba5b072c787cc75405018415bf098b77801e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 11:29:10 -0300 Subject: [PATCH 01/19] test(ganttDb.spec): add test case for inclusive end dates --- src/diagrams/gantt/ganttDb.spec.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 12e644a0d2..2601c9497e 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -125,4 +125,26 @@ describe('when using the ganttDb', function () { expect(tasks[6].id).toEqual('id7') expect(tasks[6].task).toEqual('test7') }) + + describe('when setting inclusive end dates', function () { + beforeEach(function () { + ganttDb.setDateFormat('YYYY-MM-DD', false) + ganttDb.addTask('test1', 'id1,2019-02-01,1d') + ganttDb.addTask('test2', 'id2,2019-02-01,2019-02-03') + }) + it('should automatically add one day to all end dates', function () { + const tasks = ganttDb.getTasks() + expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) + expect(tasks[0].endTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate()) + expect(tasks[0].id).toEqual('id1') + expect(tasks[0].task).toEqual('test1') + + expect(tasks[1].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) + expect(tasks[1].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()) + expect(tasks[3].renderEndTime).toBeNull() // Fixed end + expect(tasks[1].manualEndTime).toBeTruthy() + expect(tasks[1].id).toEqual('id2') + expect(tasks[1].task).toEqual('test2') + }) + }) }) From 402d4bdee17439b760df86a364f6f2f3731c62c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 11:29:50 -0300 Subject: [PATCH 02/19] test(gantt.spec): add parser test for inclusive end dates --- src/diagrams/gantt/parser/gantt.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/diagrams/gantt/parser/gantt.spec.js b/src/diagrams/gantt/parser/gantt.spec.js index ad62951802..1a066b941f 100644 --- a/src/diagrams/gantt/parser/gantt.spec.js +++ b/src/diagrams/gantt/parser/gantt.spec.js @@ -14,6 +14,12 @@ describe('when parsing a gantt diagram it', function () { parser.parse(str) }) + + it('should handle a dateFormat definition with inclusivity specified', function () { + const str = 'gantt\ndateFormat yyyy-mm-dd inclusive' + + parser.parse(str) + }) it('should handle a title definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid' From 6dce25539318b21dbbba02971256d96a89028f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 11:30:13 -0300 Subject: [PATCH 03/19] fix(ganttDb.js): clear formats and excludes on clear --- src/diagrams/gantt/ganttDb.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index cce922ea1e..4d2464ae28 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -22,6 +22,9 @@ export const clear = function () { lastTask = undefined lastTaskID = undefined rawTasks = [] + dateFormat = '' + axisFormat = '' + excludes = [] } export const setAxisFormat = function (txt) { From 6d20ccccd083104672c1d3d9f936876902ee8407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 11:54:18 -0300 Subject: [PATCH 04/19] feat(ganttDb.js): add getters for excludes,sections and date format --- src/diagrams/gantt/ganttDb.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 4d2464ae28..41a1504300 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -39,10 +39,18 @@ export const setDateFormat = function (txt) { dateFormat = txt } +export const getDateFormat = function () { + return dateFormat +} + export const setExcludes = function (txt) { excludes = txt.toLowerCase().split(/[\s,]+/) } +export const getExcludes = function () { + return excludes +} + export const setTitle = function (txt) { title = txt } @@ -56,6 +64,10 @@ export const addSection = function (txt) { sections.push(txt) } +export const getSections = function () { + return sections +} + export const getTasks = function () { let allItemsPricessed = compileTasks() const maxDepth = 10 @@ -498,16 +510,19 @@ export const bindFunctions = function (element) { export default { clear, setDateFormat, + getDateFormat, setAxisFormat, getAxisFormat, setTitle, getTitle, addSection, + getSections, getTasks, addTask, findTaskById, addTaskOrg, setExcludes, + getExcludes, setClickEvent, setLink, bindFunctions From 0515375cfa0f1f96410dcb2e9ecd0aadb8877a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 11:54:45 -0300 Subject: [PATCH 05/19] test(ganttDb.spec): clear function --- src/diagrams/gantt/ganttDb.spec.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 2601c9497e..f24239c964 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -7,6 +7,29 @@ describe('when using the ganttDb', function () { ganttDb.clear() }) + describe('when calling the clear function', function () { + beforeEach(function () { + ganttDb.setDateFormat('YYYY-MM-DD') + ganttDb.setExcludes('weekends 2019-02-06,friday') + ganttDb.addSection('weekends skip test') + ganttDb.addTask('test1', 'id1,2019-02-01,1d') + ganttDb.addTask('test2', 'id2,after id1,2d') + ganttDb.clear() + }) + + it.each` + fn | expected + ${'getTasks'} | ${[]} + ${'getTitle'} | ${''} + ${'getDateFormat'}| ${''} + ${'getAxisFormat'}| ${''} + ${'getExcludes'} | ${[]} + ${'getSections'} | ${[]} + `('should clear $fn', ({ fn, expected }) => { + expect(ganttDb[ fn ]()).toEqual(expected) +}) + }) + it.each` testName | section | taskName | taskData | expStartDate | expEndDate | expId | expTask ${'should handle fixed dates'} | ${'testa1'} | ${'test1'} | ${'id1,2013-01-01,2013-01-12'} | ${new Date(2013, 0, 1)} | ${new Date(2013, 0, 12)} | ${'id1'} | ${'test1'} From 5c2d416a34181a0e3ae54200629d1dd3661c0fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 12:25:57 -0300 Subject: [PATCH 06/19] test(ganttDB.spec): fix typo --- src/diagrams/gantt/ganttDb.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index f24239c964..67dcbc0d24 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -164,7 +164,7 @@ describe('when using the ganttDb', function () { expect(tasks[1].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) expect(tasks[1].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()) - expect(tasks[3].renderEndTime).toBeNull() // Fixed end + expect(tasks[1].renderEndTime).toBeNull() // Fixed end expect(tasks[1].manualEndTime).toBeTruthy() expect(tasks[1].id).toEqual('id2') expect(tasks[1].task).toEqual('test2') From b5b714861d68e0af796aac82a9469b6d139ffc05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 12:26:32 -0300 Subject: [PATCH 07/19] test(ganttDb.spec): flip function design to specify inclusive instead --- src/diagrams/gantt/ganttDb.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 67dcbc0d24..b787828696 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -151,7 +151,7 @@ describe('when using the ganttDb', function () { describe('when setting inclusive end dates', function () { beforeEach(function () { - ganttDb.setDateFormat('YYYY-MM-DD', false) + ganttDb.setDateFormat('YYYY-MM-DD', true) ganttDb.addTask('test1', 'id1,2019-02-01,1d') ganttDb.addTask('test2', 'id2,2019-02-01,2019-02-03') }) From 63096a5c269cfad4a02e599759be9dbc9bfbd109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 12:27:28 -0300 Subject: [PATCH 08/19] feat(ganttDb.js): add 1 day to end dates if inclusive is set to true This will essentially keep all old behavior the same while still allowing users to specify if they want inclusive end dates --- src/diagrams/gantt/ganttDb.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 41a1504300..006775acf8 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -11,6 +11,7 @@ let tasks = [] let currentSection = '' const tags = ['active', 'done', 'crit', 'milestone'] let funs = [] +let inclusiveEndDates = false export const clear = function () { sections = [] @@ -25,6 +26,7 @@ export const clear = function () { dateFormat = '' axisFormat = '' excludes = [] + inclusiveEndDates = false } export const setAxisFormat = function (txt) { @@ -35,8 +37,9 @@ export const getAxisFormat = function () { return axisFormat } -export const setDateFormat = function (txt) { +export const setDateFormat = function (txt, inclusive) { dateFormat = txt + inclusiveEndDates = inclusive || false // make sure it's not undefined } export const getDateFormat = function () { @@ -149,12 +152,16 @@ const getStartDate = function (prevTime, dateFormat, str) { return new Date() } -const getEndDate = function (prevTime, dateFormat, str) { +const getEndDate = function (prevTime, dateFormat, str, inclusive) { + inclusive = inclusive || false str = str.trim() // Check for actual date let mDate = moment(str, dateFormat.trim(), true) if (mDate.isValid()) { + if (inclusive) { + mDate.add(1, 'd') + } return mDate.toDate() } From ee766ec88ea3ba272662d99838ae47541b07921c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sat, 6 Jul 2019 12:28:56 -0300 Subject: [PATCH 09/19] fix(ganttDb): change manual end time determination now it just checks if a valid end time was provided and instead of the comparison that went on before. This needed to be done in order to support manual end dates with inclusive set to true since they don't match anymore as the 'manually' supplied end date is increased by one --- src/diagrams/gantt/ganttDb.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 006775acf8..48cfd0bb9c 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -253,8 +253,8 @@ const compileData = function (prevTask, dataStr) { } if (endTimeData) { - task.endTime = getEndDate(task.startTime, dateFormat, endTimeData) - task.manualEndTime = endTimeData === moment(task.endTime).format(dateFormat.trim()) + task.endTime = getEndDate(task.startTime, dateFormat, endTimeData, inclusiveEndDates) + task.manualEndTime = moment(endTimeData, 'YYYY-MM-DD', true).isValid() checkTaskDates(task, dateFormat, excludes) } @@ -392,10 +392,10 @@ const compileTasks = function () { } if (rawTasks[pos].startTime) { - rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, dateFormat, rawTasks[pos].raw.endTime.data) + rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, dateFormat, rawTasks[pos].raw.endTime.data, inclusiveEndDates) if (rawTasks[pos].endTime) { rawTasks[pos].processed = true - rawTasks[pos].manualEndTime = rawTasks[pos].raw.endTime.data === moment(rawTasks[pos].endTime).format(dateFormat.trim()) + rawTasks[pos].manualEndTime = moment(rawTasks[pos].raw.endTime.data, 'YYYY-MM-DD', true).isValid() checkTaskDates(rawTasks[pos], dateFormat, excludes) } } From 660e0f3d8b5fef2c05a02474658553aa0337b9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:27:28 -0300 Subject: [PATCH 10/19] refactor(ganttDb): separate out the inclusive end date toggle --- src/diagrams/gantt/ganttDb.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 48cfd0bb9c..a8a34b3136 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -37,9 +37,16 @@ export const getAxisFormat = function () { return axisFormat } -export const setDateFormat = function (txt, inclusive) { +export const setDateFormat = function (txt) { dateFormat = txt - inclusiveEndDates = inclusive || false // make sure it's not undefined +} + +export const enableInclusiveEndDates = function () { + inclusiveEndDates = true +} + +export const endDatesAreInclusive = function () { + return inclusiveEndDates } export const getDateFormat = function () { @@ -518,6 +525,8 @@ export default { clear, setDateFormat, getDateFormat, + enableInclusiveEndDates, + endDatesAreInclusive, setAxisFormat, getAxisFormat, setTitle, From 0a567a3ef91ddff2164d3a9fec482ce36bad3f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:27:41 -0300 Subject: [PATCH 11/19] test(ganttDb): update inclusive end date tests --- src/diagrams/gantt/ganttDb.spec.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index b787828696..7dbc26848f 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -18,13 +18,14 @@ describe('when using the ganttDb', function () { }) it.each` - fn | expected - ${'getTasks'} | ${[]} - ${'getTitle'} | ${''} - ${'getDateFormat'}| ${''} - ${'getAxisFormat'}| ${''} - ${'getExcludes'} | ${[]} - ${'getSections'} | ${[]} + fn | expected + ${'getTasks'} | ${[]} + ${'getTitle'} | ${''} + ${'getDateFormat'} | ${''} + ${'getAxisFormat'} | ${''} + ${'getExcludes'} | ${[]} + ${'getSections'} | ${[]} + ${'endDatesAreInclusive'} | ${false} `('should clear $fn', ({ fn, expected }) => { expect(ganttDb[ fn ]()).toEqual(expected) }) @@ -151,7 +152,8 @@ describe('when using the ganttDb', function () { describe('when setting inclusive end dates', function () { beforeEach(function () { - ganttDb.setDateFormat('YYYY-MM-DD', true) + ganttDb.setDateFormat('YYYY-MM-DD') + ganttDb.enableInclusiveEndDates() ganttDb.addTask('test1', 'id1,2019-02-01,1d') ganttDb.addTask('test2', 'id2,2019-02-01,2019-02-03') }) From 16f3338b3d1a3af573a764d4fe89fce7d65d4cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:28:31 -0300 Subject: [PATCH 12/19] feat(gantt.jison): update parser to accept a inclusive end date arg if a line contains inclusiveEndDates then it will toggle the chart to use inclusive end dates --- src/diagrams/gantt/parser/gantt.jison | 8 +++++--- src/diagrams/gantt/parser/gantt.spec.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/diagrams/gantt/parser/gantt.jison b/src/diagrams/gantt/parser/gantt.jison index d28a79d973..ea76b59a19 100644 --- a/src/diagrams/gantt/parser/gantt.jison +++ b/src/diagrams/gantt/parser/gantt.jison @@ -55,6 +55,7 @@ that id. "gantt" return 'gantt'; "dateFormat"\s[^#\n;]+ return 'dateFormat'; +"inclusiveEndDates" return 'inclusiveEndDates'; "axisFormat"\s[^#\n;]+ return 'axisFormat'; "excludes"\s[^#\n;]+ return 'excludes'; \d\d\d\d"-"\d\d"-"\d\d return 'date'; @@ -91,9 +92,10 @@ line ; statement - : 'dateFormat' {yy.setDateFormat($1.substr(11));$$=$1.substr(11);} - | 'axisFormat' {yy.setAxisFormat($1.substr(11));$$=$1.substr(11);} - | 'excludes' {yy.setExcludes($1.substr(9));$$=$1.substr(9);} + : dateFormat {yy.setDateFormat($1.substr(11));$$=$1.substr(11);} + | inclusiveEndDates {yy.enableInclusiveEndDates();$$=$1.substr(18);} + | axisFormat {yy.setAxisFormat($1.substr(11));$$=$1.substr(11);} + | excludes {yy.setExcludes($1.substr(9));$$=$1.substr(9);} | title {yy.setTitle($1.substr(6));$$=$1.substr(6);} | section {yy.addSection($1.substr(8));$$=$1.substr(8);} | clickStatement diff --git a/src/diagrams/gantt/parser/gantt.spec.js b/src/diagrams/gantt/parser/gantt.spec.js index 1a066b941f..c6d8af2853 100644 --- a/src/diagrams/gantt/parser/gantt.spec.js +++ b/src/diagrams/gantt/parser/gantt.spec.js @@ -15,8 +15,8 @@ describe('when parsing a gantt diagram it', function () { parser.parse(str) }) - it('should handle a dateFormat definition with inclusivity specified', function () { - const str = 'gantt\ndateFormat yyyy-mm-dd inclusive' + it('should handle a inclusive end date definition', function () { + const str = 'gantt\ndateFormat yyyy-mm-dd\ninclusiveEndDates' parser.parse(str) }) From cb7d05bd53fb051a297be2e9a67e6ba83a610602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:28:53 -0300 Subject: [PATCH 13/19] chore(gantt.js): generate parser from jison --- src/diagrams/gantt/parser/gantt.js | 124 +++++++++++++++-------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/src/diagrams/gantt/parser/gantt.js b/src/diagrams/gantt/parser/gantt.js index 1b85efadd1..44fcbecb6b 100644 --- a/src/diagrams/gantt/parser/gantt.js +++ b/src/diagrams/gantt/parser/gantt.js @@ -71,13 +71,13 @@ recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) } */ -var parser = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,8,10,11,12,13,14,15,17,19],$V1=[1,9],$V2=[1,10],$V3=[1,11],$V4=[1,12],$V5=[1,13],$V6=[1,15],$V7=[1,16]; +var gantt = (function(){ +var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[6,8,10,11,12,13,14,15,16,18,20],$V1=[1,9],$V2=[1,10],$V3=[1,11],$V4=[1,12],$V5=[1,13],$V6=[1,14],$V7=[1,16],$V8=[1,17]; var parser = {trace: function trace () { }, yy: {}, -symbols_: {"error":2,"start":3,"gantt":4,"document":5,"EOF":6,"line":7,"SPACE":8,"statement":9,"NL":10,"dateFormat":11,"axisFormat":12,"excludes":13,"title":14,"section":15,"clickStatement":16,"taskTxt":17,"taskData":18,"click":19,"callbackname":20,"callbackargs":21,"href":22,"clickStatementDebug":23,"$accept":0,"$end":1}, -terminals_: {2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",11:"dateFormat",12:"axisFormat",13:"excludes",14:"title",15:"section",17:"taskTxt",18:"taskData",19:"click",20:"callbackname",21:"callbackargs",22:"href"}, -productions_: [0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[16,2],[16,3],[16,3],[16,4],[16,3],[16,4],[16,2],[23,2],[23,3],[23,3],[23,4],[23,3],[23,4],[23,2]], +symbols_: {"error":2,"start":3,"gantt":4,"document":5,"EOF":6,"line":7,"SPACE":8,"statement":9,"NL":10,"dateFormat":11,"inclusiveEndDates":12,"axisFormat":13,"excludes":14,"title":15,"section":16,"clickStatement":17,"taskTxt":18,"taskData":19,"click":20,"callbackname":21,"callbackargs":22,"href":23,"clickStatementDebug":24,"$accept":0,"$end":1}, +terminals_: {2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",11:"dateFormat",12:"inclusiveEndDates",13:"axisFormat",14:"excludes",15:"title",16:"section",18:"taskTxt",19:"taskData",20:"click",21:"callbackname",22:"callbackargs",23:"href"}, +productions_: [0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[17,2],[17,3],[17,3],[17,4],[17,3],[17,4],[17,2],[24,2],[24,3],[24,3],[24,4],[24,3],[24,4],[24,2]], performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { /* this == yyval */ @@ -102,53 +102,56 @@ case 8: yy.setDateFormat($$[$0].substr(11));this.$=$$[$0].substr(11); break; case 9: -yy.setAxisFormat($$[$0].substr(11));this.$=$$[$0].substr(11); +yy.enableInclusiveEndDates();this.$=$$[$0].substr(18); break; case 10: -yy.setExcludes($$[$0].substr(9));this.$=$$[$0].substr(9); +yy.setAxisFormat($$[$0].substr(11));this.$=$$[$0].substr(11); break; case 11: -yy.setTitle($$[$0].substr(6));this.$=$$[$0].substr(6); +yy.setExcludes($$[$0].substr(9));this.$=$$[$0].substr(9); break; case 12: +yy.setTitle($$[$0].substr(6));this.$=$$[$0].substr(6); +break; +case 13: yy.addSection($$[$0].substr(8));this.$=$$[$0].substr(8); break; -case 14: +case 15: yy.addTask($$[$0-1],$$[$0]);this.$='task'; break; -case 15: +case 16: this.$ = $$[$0-1];yy.setClickEvent($$[$0-1], $$[$0], null); break; -case 16: +case 17: this.$ = $$[$0-2];yy.setClickEvent($$[$0-2], $$[$0-1], $$[$0]); break; -case 17: +case 18: this.$ = $$[$0-2];yy.setClickEvent($$[$0-2], $$[$0-1], null);yy.setLink($$[$0-2],$$[$0]); break; -case 18: +case 19: this.$ = $$[$0-3];yy.setClickEvent($$[$0-3], $$[$0-2], $$[$0-1]);yy.setLink($$[$0-3],$$[$0]); break; -case 19: +case 20: this.$ = $$[$0-2];yy.setClickEvent($$[$0-2], $$[$0], null);yy.setLink($$[$0-2],$$[$0-1]); break; -case 20: +case 21: this.$ = $$[$0-3];yy.setClickEvent($$[$0-3], $$[$0-1], $$[$0]);yy.setLink($$[$0-3],$$[$0-2]); break; -case 21: +case 22: this.$ = $$[$0-1];yy.setLink($$[$0-1], $$[$0]); break; -case 22: case 28: +case 23: case 29: this.$=$$[$0-1] + ' ' + $$[$0]; break; -case 23: case 24: case 26: +case 24: case 25: case 27: this.$=$$[$0-2] + ' ' + $$[$0-1] + ' ' + $$[$0]; break; -case 25: case 27: +case 26: case 28: this.$=$$[$0-3] + ' ' + $$[$0-2] + ' ' + $$[$0-1] + ' ' + $$[$0]; break; } }, -table: [{3:1,4:[1,2]},{1:[3]},o($V0,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:$V1,12:$V2,13:$V3,14:$V4,15:$V5,16:14,17:$V6,19:$V7},o($V0,[2,7],{1:[2,1]}),o($V0,[2,3]),{9:17,11:$V1,12:$V2,13:$V3,14:$V4,15:$V5,16:14,17:$V6,19:$V7},o($V0,[2,5]),o($V0,[2,6]),o($V0,[2,8]),o($V0,[2,9]),o($V0,[2,10]),o($V0,[2,11]),o($V0,[2,12]),o($V0,[2,13]),{18:[1,18]},{20:[1,19],22:[1,20]},o($V0,[2,4]),o($V0,[2,14]),o($V0,[2,15],{21:[1,21],22:[1,22]}),o($V0,[2,21],{20:[1,23]}),o($V0,[2,16],{22:[1,24]}),o($V0,[2,17]),o($V0,[2,19],{21:[1,25]}),o($V0,[2,18]),o($V0,[2,20])], +table: [{3:1,4:[1,2]},{1:[3]},o($V0,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:$V1,12:$V2,13:$V3,14:$V4,15:$V5,16:$V6,17:15,18:$V7,20:$V8},o($V0,[2,7],{1:[2,1]}),o($V0,[2,3]),{9:18,11:$V1,12:$V2,13:$V3,14:$V4,15:$V5,16:$V6,17:15,18:$V7,20:$V8},o($V0,[2,5]),o($V0,[2,6]),o($V0,[2,8]),o($V0,[2,9]),o($V0,[2,10]),o($V0,[2,11]),o($V0,[2,12]),o($V0,[2,13]),o($V0,[2,14]),{19:[1,19]},{21:[1,20],23:[1,21]},o($V0,[2,4]),o($V0,[2,15]),o($V0,[2,16],{22:[1,22],23:[1,23]}),o($V0,[2,22],{21:[1,24]}),o($V0,[2,17],{23:[1,25]}),o($V0,[2,18]),o($V0,[2,20],{22:[1,26]}),o($V0,[2,19]),o($V0,[2,21])], defaultActions: {}, parseError: function parseError (str, hash) { if (hash.recoverable) { @@ -188,18 +191,15 @@ parse: function parse(input) { vstack.length = vstack.length - n; lstack.length = lstack.length - n; } - function lex() { + _token_stack: + var lex = function () { var token; - token = tstack.pop() || lexer.lex() || EOF; + token = lexer.lex() || EOF; if (typeof token !== 'number') { - if (token instanceof Array) { - tstack = token; - token = tstack.pop(); - } token = self.symbols_[token] || token; } return token; - } + }; var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; while (true) { state = stack[stack.length - 1]; @@ -211,27 +211,27 @@ parse: function parse(input) { } action = table[state] && table[state][symbol]; } - if (typeof action === 'undefined' || !action.length || !action[0]) { - var errStr = ''; - expected = []; - for (p in table[state]) { - if (this.terminals_[p] && p > TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); + if (typeof action === 'undefined' || !action.length || !action[0]) { + var errStr = ''; + expected = []; + for (p in table[state]) { + if (this.terminals_[p] && p > TERROR) { + expected.push('\'' + this.terminals_[p] + '\''); + } } + if (lexer.showPosition) { + errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; + } else { + errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + } + this.parseError(errStr, { + text: lexer.match, + token: this.terminals_[symbol] || symbol, + line: lexer.yylineno, + loc: yyloc, + expected: expected + }); } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); - } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); - } if (action[0] instanceof Array && action.length > 1) { throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); } @@ -640,7 +640,7 @@ case 4:this.begin("href"); break; case 5:this.popState(); break; -case 6:return 22; +case 6:return 23; break; case 7:this.begin("callbackname"); break; @@ -648,17 +648,17 @@ case 8:this.popState(); break; case 9:this.popState(); this.begin("callbackargs"); break; -case 10:return 20; +case 10:return 21; break; case 11:this.popState(); break; -case 12:return 21; +case 12:return 22; break; case 13:this.begin("click"); break; case 14:this.popState(); break; -case 15:return 19; +case 15:return 20; break; case 16:return 4; break; @@ -668,26 +668,28 @@ case 18:return 12; break; case 19:return 13; break; -case 20:return 'date'; +case 20:return 14; break; -case 21:return 14; +case 21:return 'date'; break; case 22:return 15; break; -case 23:return 17; +case 23:return 16; break; case 24:return 18; break; -case 25:return ':'; +case 25:return 19; +break; +case 26:return ':'; break; -case 26:return 6; +case 27:return 6; break; -case 27:return 'INVALID'; +case 28:return 'INVALID'; break; } }, -rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i], -conditions: {"callbackargs":{"rules":[11,12],"inclusive":false},"callbackname":{"rules":[8,9,10],"inclusive":false},"href":{"rules":[5,6],"inclusive":false},"click":{"rules":[14,15],"inclusive":false},"INITIAL":{"rules":[0,1,2,3,4,7,13,16,17,18,19,20,21,22,23,24,25,26,27],"inclusive":true}} +rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i], +conditions: {"callbackargs":{"rules":[11,12],"inclusive":false},"callbackname":{"rules":[8,9,10],"inclusive":false},"href":{"rules":[5,6],"inclusive":false},"click":{"rules":[14,15],"inclusive":false},"INITIAL":{"rules":[0,1,2,3,4,7,13,16,17,18,19,20,21,22,23,24,25,26,27,28],"inclusive":true}} }); return lexer; })(); @@ -701,9 +703,9 @@ return new Parser; if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = parser; -exports.Parser = parser.Parser; -exports.parse = function () { return parser.parse.apply(parser, arguments); }; +exports.parser = gantt; +exports.Parser = gantt.Parser; +exports.parse = function () { return gantt.parse.apply(gantt, arguments); }; exports.main = function commonjsMain (args) { if (!args[1]) { console.log('Usage: '+args[0]+' FILE'); From 1ee4b964e2bb3ebbeaf0cf1705262619e32d2124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:41:07 -0300 Subject: [PATCH 14/19] test(gantt.spec): add assertions to check that the parser didn't error --- src/diagrams/gantt/parser/gantt.spec.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/diagrams/gantt/parser/gantt.spec.js b/src/diagrams/gantt/parser/gantt.spec.js index c6d8af2853..7a28aeb6c2 100644 --- a/src/diagrams/gantt/parser/gantt.spec.js +++ b/src/diagrams/gantt/parser/gantt.spec.js @@ -3,6 +3,12 @@ import { parser } from './gantt' import ganttDb from '../ganttDb' +const parserFnConstructor = (str) => { + return () => { + parser.parse(str) + } +} + describe('when parsing a gantt diagram it', function () { beforeEach(function () { parser.yy = ganttDb @@ -12,23 +18,23 @@ describe('when parsing a gantt diagram it', function () { it('should handle a dateFormat definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() }) it('should handle a inclusive end date definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ninclusiveEndDates' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() }) it('should handle a title definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() }) it('should handle an excludes definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid\nexcludes weekdays 2019-02-01' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() }) it('should handle a section definition', function () { const str = 'gantt\n' + @@ -37,7 +43,7 @@ describe('when parsing a gantt diagram it', function () { 'excludes weekdays 2019-02-01\n' + 'section Documentation' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() }) /** * Beslutsflöde inligt nedan. Obs bla bla bla @@ -57,7 +63,7 @@ describe('when parsing a gantt diagram it', function () { 'section Documentation\n' + 'Design jison grammar:des1, 2014-01-01, 2014-01-04' - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() const tasks = parser.yy.getTasks() @@ -82,7 +88,7 @@ describe('when parsing a gantt diagram it', function () { const allowedTags = ['active', 'done', 'crit', 'milestone'] - parser.parse(str) + expect(parserFnConstructor(str)).not.toThrow() const tasks = parser.yy.getTasks() From a671576578232e4c8be4ed8cc580a63cc93f7c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 16:51:40 -0300 Subject: [PATCH 15/19] feat(index.html): add example to display new behavior --- dist/index.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dist/index.html b/dist/index.html index a70cb14dab..22c956d776 100644 --- a/dist/index.html +++ b/dist/index.html @@ -7,6 +7,26 @@ +
+ gantt + title Exclusive end dates (Manual date should end on 3d) + dateFormat YYYY-MM-DD + axisFormat %d + section Section1 + 2 Days: 1, 2019-01-01,2d + Manual Date: 2, 2019-01-01,2019-01-03 +
+ +
+ gantt + title Inclusive end dates (Manual date should end on 4th) + dateFormat YYYY-MM-DD + axisFormat %d + inclusiveEndDates + section Section1 + 2 Days: 1, 2019-01-01,2d + Manual Date: 2, 2019-01-01,2019-01-03 +
graph LR sid-B3655226-6C29-4D00-B685-3D5C734DC7E1[" From 67bb5ffa734f8111c513f129165cf4e941e969b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 17:01:45 -0300 Subject: [PATCH 16/19] refactor(ganttDb.js): extract durationToDate function codeclimate was complaining about the getEndDate function so I split it up --- src/diagrams/gantt/ganttDb.js | 50 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index a8a34b3136..98b8045ccd 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -159,45 +159,47 @@ const getStartDate = function (prevTime, dateFormat, str) { return new Date() } -const getEndDate = function (prevTime, dateFormat, str, inclusive) { - inclusive = inclusive || false - str = str.trim() - - // Check for actual date - let mDate = moment(str, dateFormat.trim(), true) - if (mDate.isValid()) { - if (inclusive) { - mDate.add(1, 'd') - } - return mDate.toDate() - } - - const d = moment(prevTime) - // Check for length - const re = /^([\d]+)([wdhms])/ - const durationStatement = re.exec(str.trim()) - +const durationToDate = function (durationStatement, relativeTime) { if (durationStatement !== null) { switch (durationStatement[2]) { case 's': - d.add(durationStatement[1], 'seconds') + relativeTime.add(durationStatement[1], 'seconds') break case 'm': - d.add(durationStatement[1], 'minutes') + relativeTime.add(durationStatement[1], 'minutes') break case 'h': - d.add(durationStatement[1], 'hours') + relativeTime.add(durationStatement[1], 'hours') break case 'd': - d.add(durationStatement[1], 'days') + relativeTime.add(durationStatement[1], 'days') break case 'w': - d.add(durationStatement[1], 'weeks') + relativeTime.add(durationStatement[1], 'weeks') break } } // Default date - now - return d.toDate() + return relativeTime.toDate() +} + +const getEndDate = function (prevTime, dateFormat, str, inclusive) { + inclusive = inclusive || false + str = str.trim() + + // Check for actual date + let mDate = moment(str, dateFormat.trim(), true) + if (mDate.isValid()) { + if (inclusive) { + mDate.add(1, 'd') + } + return mDate.toDate() + } + + return durationToDate( + /^([\d]+)([wdhms])/.exec(str.trim()), + moment(prevTime) + ) } let taskCnt = 0 From b7c4b66b61a246c342faf88edc93487ff41d5c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 17:04:40 -0300 Subject: [PATCH 17/19] test(ganttDb.spec): fix missing initialization for clear test --- src/diagrams/gantt/ganttDb.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 7dbc26848f..6bea54bc5d 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -10,6 +10,7 @@ describe('when using the ganttDb', function () { describe('when calling the clear function', function () { beforeEach(function () { ganttDb.setDateFormat('YYYY-MM-DD') + ganttDb.enableInclusiveEndDates() ganttDb.setExcludes('weekends 2019-02-06,friday') ganttDb.addSection('weekends skip test') ganttDb.addTask('test1', 'id1,2019-02-01,1d') From 047760ad4bebb9dbce11b0bbce75bdfe9144b4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 17:17:05 -0300 Subject: [PATCH 18/19] chore(ganttDb): export durationToDate so it can be tested --- src/diagrams/gantt/ganttDb.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 98b8045ccd..c2a9f82b58 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -543,7 +543,8 @@ export default { getExcludes, setClickEvent, setLink, - bindFunctions + bindFunctions, + durationToDate } function getTaskTags (data, task, tags) { From c6511ed829375ba1d36ce358008d2a63e4e3ef14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20W=C3=BCrtz?= Date: Sun, 7 Jul 2019 17:17:22 -0300 Subject: [PATCH 19/19] test(ganttDb.spec): add simple tests for the durationToDate fn --- src/diagrams/gantt/ganttDb.spec.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 6bea54bc5d..1dad71ad6b 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -7,6 +7,16 @@ describe('when using the ganttDb', function () { ganttDb.clear() }) + describe('when using relative times', function () { + it.each` + diff | date | expected + ${' 1d'} | ${moment('2019-01-01')} | ${moment('2019-01-02').toDate()} + ${' 1w'} | ${moment('2019-01-01')} | ${moment('2019-01-08').toDate()} + `('should add $diff to $date resulting in $expected', ({ diff, date, expected }) => { + expect(ganttDb.durationToDate(diff, date)).toEqual(expected) +}) + }) + describe('when calling the clear function', function () { beforeEach(function () { ganttDb.setDateFormat('YYYY-MM-DD')