From d69a8aeb63e59a04c63d91b6c11c775a7e4f8477 Mon Sep 17 00:00:00 2001 From: Subhash Halder Date: Sat, 1 Jul 2023 22:14:33 +0530 Subject: [PATCH] Added full jison for bar and line chart --- .../src/diagrams/xychart/parser/xychart.jison | 162 +++++++++++------- .../xychart/parser/xychart.jison.spec.ts | 58 ++++++- 2 files changed, 155 insertions(+), 65 deletions(-) diff --git a/packages/mermaid/src/diagrams/xychart/parser/xychart.jison b/packages/mermaid/src/diagrams/xychart/parser/xychart.jison index 66e160ac0..047eeebc5 100644 --- a/packages/mermaid/src/diagrams/xychart/parser/xychart.jison +++ b/packages/mermaid/src/diagrams/xychart/parser/xychart.jison @@ -21,81 +21,107 @@ %x axis_data_band %x axis_data_band_capture %x axis_data_band_str +%x line +%x line_title +%x line_data +%x line_data_entries +%x bar +%x bar_title +%x bar_data +%x bar_data_entries %% -\%\%\{ { this.begin('open_directive'); return 'open_directive'; } -((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } -":" { this.popState(); this.begin('arg_directive'); return ':'; } -\}\%\% { this.popState(); this.popState(); return 'close_directive'; } -((?:(?!\}\%\%).|\n)*) return 'arg_directive'; -\%\%(?!\{)[^\n]* /* skip comments */ -[^\}]\%\%[^\n]* /* skip comments */ -[\n\r]+ return 'NEWLINE'; -\%\%[^\n]* /* do nothing */ +\%\%\{ { this.begin('open_directive'); return 'open_directive'; } +((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } +":" { this.popState(); this.begin('arg_directive'); return ':'; } +\}\%\% { this.popState(); this.popState(); return 'close_directive'; } +((?:(?!\}\%\%).|\n)*) return 'arg_directive'; +\%\%(?!\{)[^\n]* /* skip comments */ +[^\}]\%\%[^\n]* /* skip comments */ +[\n\r]+ return 'NEWLINE'; +\%\%[^\n]* /* do nothing */ -title { this.begin("title");return 'title'; } -(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; } +title { this.begin("title");return 'title'; } +<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; } -accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } -<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } -accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } -<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; } -accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} -<acc_descr_multiline>[\}] { this.popState(); } -<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value"; +accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } +<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } +accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } +<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; } +accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} +<acc_descr_multiline>[\}] { this.popState(); } +<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value"; -" "*"xychart-beta" {this.begin("chart_config"); return 'XYCHART';} +" "*"xychart-beta" {this.begin("chart_config"); return 'XYCHART';} <chart_config>" "+("vertical"|"horizontal") {this.begin("chart_orientation"); return 'chart_orientation';} -<chart_orientation>[\s]* {this.popState(); this.popState(); return 'CHART_CONFIG_END';} -<chart_config>[\s]* {this.popState(); return 'CHART_CONFIG_END';} +<chart_orientation>[\s]* {this.popState(); this.popState(); return 'CHART_CONFIG_END';} +<chart_config>[\s]* {this.popState(); return 'CHART_CONFIG_END';} -"x-axis"" "* { this.begin("x_axis"); return "X_AXIS";} -"y-axis"" "* { this.begin("y_axis"); return "Y_AXIS";} -<x_axis,y_axis>["] {this.begin("axis_title");} -<axis_title>[^"]+ {return 'AXIS_TITLE';} -<axis_title>["]" "*(\r?\n) {this.popState(); this.popState();} -<axis_title>["]" "* {this.popState(); this.begin("axis_data");} -<x_axis,y_axis>[^\s]+" "*(\r?\n) {this.popState(); return 'AXIS_TITLE';} -<x_axis,y_axis>[^\s]+" "* {this.begin("axis_data"); return 'AXIS_TITLE'; } +"x-axis"" "* { this.begin("x_axis"); return "X_AXIS";} +"y-axis"" "* { this.begin("y_axis"); return "Y_AXIS";} +<x_axis,y_axis>["] {this.begin("axis_title");} +<axis_title>[^"]+ {return 'AXIS_TITLE';} +<axis_title>["]" "*(\r?\n) {this.popState(); this.popState();} +<axis_title>["]" "* {this.popState(); this.begin("axis_data");} +<x_axis,y_axis>[^\s]+" "*(\r?\n) {this.popState(); return 'AXIS_TITLE';} +<x_axis,y_axis>[^\s]+" "* {this.begin("axis_data"); return 'AXIS_TITLE'; } -<axis_data>[+-]?\d+(\.\d+)?" "*"-->"" "*[+-]?\d+(\.\d+)?" "* { return 'AXIS_RANGE_DATA';} +<axis_data>[+-]?\d+(?:\.\d+)?" "*"-->"" "*[+-]?\d+(?:\.\d+)?" "* { return 'AXIS_RANGE_DATA';} -<axis_data>[\[]" "* {this.begin("axis_data_band"); this.begin("axis_data_band_capture")} -<axis_data_band>[,]" "* {this.begin("axis_data_band_capture")} -<axis_data_band_capture>["] {this.begin("axis_data_band_str");} -<axis_data_band_str>[^"]+ {return "AXIS_BAND_DATA";} -<axis_data_band_str>["]" "* {this.popState(); this.popState();} -<axis_data_band_capture>[^\s]+" "* {this.popState(); return "AXIS_BAND_DATA"} -<axis_data_band>[\]]" "* {this.popState(); return "AXIS_BAND_DATA_END"} +<axis_data>[\[]" "* {this.begin("axis_data_band"); this.begin("axis_data_band_capture")} +<axis_data_band>[,]" "* {this.begin("axis_data_band_capture")} +<axis_data_band_capture>["] {this.begin("axis_data_band_str");} +<axis_data_band_str>[^"]+ {return "AXIS_BAND_DATA";} +<axis_data_band_str>["]" "* {this.popState(); this.popState();} +<axis_data_band_capture>[^\s]+" "* {this.popState(); return "AXIS_BAND_DATA"} +<axis_data_band>[\]]" "* {this.popState(); return "AXIS_BAND_DATA_END"} +<axis_data>[\r\n]+ {this.popState(); this.popState();} -<axis_data>[\r\n]+ {this.popState(); this.popState();} +"line"" "* {this.begin("line"); return 'LINE';} +<line>["] {this.begin("line_title");} +<line_title>[^"]+ {return 'LINE_TITLE';} +<line_title>["]" "* {this.popState(); this.begin("line_data");} +<line_data>"["" "* {this.begin('line_data_entries');} +<line_data_entries>(?:[+-]?\d+(?:\.\d+)?)+(?:" "*[,]" "*(?:[+-]?\d+(?:\.\d+)?)+)*" "* {return 'LINE_DATA'} +<line_data_entries>"]"" "* {this.popState(); this.popState(); this.popState()} +<line>[^\s]+" "* {this.begin("line_data"); return 'LINE_TITLE';} + +"bar"" "* {this.begin("bar"); return 'BAR';} +<bar>["] {this.begin("bar_title");} +<bar_title>[^"]+ {return 'BAR_TITLE';} +<bar_title>["]" "* {this.popState(); this.begin("bar_data");} +<bar_data>"["" "* {this.begin('bar_data_entries');} +<bar_data_entries>(?:[+-]?\d+(?:\.\d+)?)+(?:" "*[,]" "*(?:[+-]?\d+(?:\.\d+)?)+)*" "* {return 'BAR_DATA'} +<bar_data_entries>"]"" "* {this.popState(); this.popState(); this.popState()} +<bar>[^\s]+" "* {this.begin("bar_data"); return 'BAR_TITLE';} -["][`] { this.begin("md_string");} -<md_string>[^`"]+ { return "MD_STR";} -<md_string>[`]["] { this.popState();} -["] this.begin("string"); -<string>["] this.popState(); -<string>[^"]* return "STR"; -[A-Za-z]+ return 'ALPHA'; -":" return 'COLON'; -\+ return 'PLUS'; -"," return 'COMMA'; -"=" return 'EQUALS'; -\= return 'EQUALS'; -"*" return 'MULT'; -\# return 'BRKT'; -[\_] return 'UNDERSCORE'; -"." return 'DOT'; -"&" return 'AMP'; -\- return 'MINUS'; -[0-9]+ return 'NUM'; -\s return 'SPACE'; -";" return 'SEMI'; -[!"#$%&'*+,-.`?\\_/] return 'PUNCTUATION'; -<<EOF>> return 'EOF'; +["][`] { this.begin("md_string");} +<md_string>[^`"]+ { return "MD_STR";} +<md_string>[`]["] { this.popState();} +["] this.begin("string"); +<string>["] this.popState(); +<string>[^"]* return "STR"; + +[A-Za-z]+ return 'ALPHA'; +":" return 'COLON'; +\+ return 'PLUS'; +"," return 'COMMA'; +"=" return 'EQUALS'; +\= return 'EQUALS'; +"*" return 'MULT'; +\# return 'BRKT'; +[\_] return 'UNDERSCORE'; +"." return 'DOT'; +"&" return 'AMP'; +\- return 'MINUS'; +[0-9]+ return 'NUM'; +\s return 'SPACE'; +";" return 'SEMI'; +[!"#$%&'*+,-.`?\\_/] return 'PUNCTUATION'; +<<EOF>> return 'EOF'; /lex @@ -130,10 +156,20 @@ statement | directive | X_AXIS parseXAxis | Y_AXIS parseYAxis + | parseLine + | parseBar ; +parseLine + : LINE LINE_TITLE LINE_DATA {yy.addLineData($2.trim(), $3.split(',').map(d => Number(d.trim())));} + ; + +parseBar + : BAR BAR_TITLE BAR_DATA {yy.addBarData($2.trim(), $3.split(',').map(d => Number(d.trim())));} + ; + parseXAxis - : AXIS_TITLE {yy.setXAxisTitle($1.trim());} + : AXIS_TITLE statement {yy.setXAxisTitle($1.trim());} | AXIS_TITLE xAxisBandData {yy.setXAxisTitle($1.trim());} | AXIS_TITLE AXIS_RANGE_DATA {yy.setXAxisTitle($1.trim()); $$ = $2.split("-->"); yy.setXAxisRangeData(Number($$[0]), Number($$[1]));} ; @@ -144,7 +180,7 @@ xAxisBandData ; parseYAxis - : AXIS_TITLE {yy.setYAxisTitle($1.trim());} + : AXIS_TITLE statement {yy.setYAxisTitle($1.trim());} | AXIS_TITLE AXIS_RANGE_DATA {yy.setYAxisTitle($1.trim()); $$ = $2.split("-->"); yy.setYAxisRangeData(Number($$[0]), Number($$[1]));} ; diff --git a/packages/mermaid/src/diagrams/xychart/parser/xychart.jison.spec.ts b/packages/mermaid/src/diagrams/xychart/parser/xychart.jison.spec.ts index 029e90356..1ce73abf3 100644 --- a/packages/mermaid/src/diagrams/xychart/parser/xychart.jison.spec.ts +++ b/packages/mermaid/src/diagrams/xychart/parser/xychart.jison.spec.ts @@ -17,6 +17,8 @@ const mockDB: Record<string, Mock<any, any>> = { setYAxisTitle: vi.fn(), setYAxisRangeData: vi.fn(), addYAxisBand: vi.fn(), + addLineData: vi.fn(), + addBarData: vi.fn(), }; function clearMocks() { @@ -104,8 +106,8 @@ describe('Testing xychart jison file', () => { expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); expect(mockDB.addXAxisBand).toHaveBeenCalledTimes(2); - expect(mockDB.addXAxisBand).toHaveBeenNthCalledWith(1, "cat2"); - expect(mockDB.addXAxisBand).toHaveBeenNthCalledWith(2, "cat1"); + expect(mockDB.addXAxisBand).toHaveBeenNthCalledWith(1, 'cat2'); + expect(mockDB.addXAxisBand).toHaveBeenNthCalledWith(2, 'cat1'); }); it('parse y-axis', () => { let str = 'xychart-beta \ny-axis yAxisName\n'; @@ -135,6 +137,58 @@ describe('Testing xychart jison file', () => { expect(parserFnConstructor(str)).not.toThrow(); expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); expect(mockDB.setYAxisRangeData).toHaveBeenCalledWith(45.5, 33); + }); + it('parse line Data', () => { + let str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line lineTitle [23, 45, 56.6]'; + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); + expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); + expect(mockDB.addLineData).toHaveBeenCalledWith('lineTitle', [23, 45, 56.6]); + clearMocks(); + + str = + 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -45 , 56.6 ] '; + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); + expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); + expect(mockDB.addLineData).toHaveBeenCalledWith('lineTitle with space', [23, -45, 56.6]); + + clearMocks(); + str = + 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n line "lineTitle with space" [ +23 , -4aa5 , 56.6 ] '; + expect(parserFnConstructor(str)).toThrow(); + }); + it('parse bar Data', () => { + let str = 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle [23, 45, 56.6]'; + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); + expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); + expect(mockDB.addBarData).toHaveBeenCalledWith('barTitle', [23, 45, 56.6]); + + clearMocks(); + + str = + 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -45 , 56.6 ] '; + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); + expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); + expect(mockDB.addBarData).toHaveBeenCalledWith('barTitle with space', [23, -45, 56.6]); + clearMocks(); + + str = + 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar "barTitle with space" [ +23 , -4aa5 , 56.6 ] '; + expect(parserFnConstructor(str)).toThrow(); + }); + it('parse multiple bar and line', () => { + let str = + 'xychart-beta\nx-axis xAxisName\ny-axis yAxisName\n bar barTitle1 [23, 45, 56.6] \n line lineTitle1 [11, 45.5, 67, 23] \n bar barTitle2 [13, 42, 56.89] \n line lineTitle2 [45, 99, 012]'; + expect(parserFnConstructor(str)).not.toThrow(); + expect(mockDB.setYAxisTitle).toHaveBeenCalledWith('yAxisName'); + expect(mockDB.setXAxisTitle).toHaveBeenCalledWith('xAxisName'); + expect(mockDB.addBarData).toHaveBeenCalledWith('barTitle1', [23, 45, 56.6]); + expect(mockDB.addBarData).toHaveBeenCalledWith('barTitle2', [13, 42, 56.89]); + expect(mockDB.addLineData).toHaveBeenCalledWith('lineTitle1', [11, 45.5, 67, 23]); + expect(mockDB.addLineData).toHaveBeenCalledWith('lineTitle2', [45, 99, 12]); }); });