diff --git a/demos/sankey.html b/demos/sankey.html
index d6ae1d2ec..d49bfc77e 100644
--- a/demos/sankey.html
+++ b/demos/sankey.html
@@ -15,92 +15,78 @@
Sankey diagram demos
- Simple example
-
- sankey
-
- node[title="hello, how are you?"]
- node[title="hello, mister Sankey"]
-
- First -> 30 -> Second
- First -> 10 -> Third
- Second -> 20 -> Third
-
-
-
Energy flow
sankey
- "Agricultural 'waste'" -> 124.729 -> "Bio-conversion"
- "Bio-conversion" -> 0.597 -> "Liquid"
- "Bio-conversion" -> 26.862 -> "Losses"
- "Bio-conversion" -> 280.322 -> "Solid"
- "Bio-conversion" -> 81.144 -> "Gas"
- "Biofuel imports" -> 35 -> "Liquid"
- "Biomass imports" -> 35 -> "Solid"
- "Coal imports" -> 11.606 -> "Coal"
- "Coal reserves" -> 63.965 -> "Coal"
- "Coal" -> 75.571 -> "Solid"
- "District heating" -> 10.639 -> "Industry"
- "District heating" -> 22.505 -> "Heating and cooling - commercial"
- "District heating" -> 46.184 -> "Heating and cooling - homes"
- "Electricity grid" -> 104.453 -> "Over generation / exports"
- "Electricity grid" -> 113.726 -> "Heating and cooling - homes"
- "Electricity grid" -> 27.14 -> "H2 conversion"
- "Electricity grid" -> 342.165 -> "Industry"
- "Electricity grid" -> 37.797 -> "Road transport"
- "Electricity grid" -> 4.412 -> "Agriculture"
- "Electricity grid" -> 40.858 -> "Heating and cooling - commercial"
- "Electricity grid" -> 56.691 -> "Losses"
- "Electricity grid" -> 7.863 -> "Rail transport"
- "Electricity grid" -> 90.008 -> "Lighting & appliances - commercial"
- "Electricity grid" -> 93.494 -> "Lighting & appliances - homes"
- "Gas imports" -> 40.719 -> "Ngas"
- "Gas reserves" -> 82.233 -> "Ngas"
- "Gas" -> 0.129 -> "Heating and cooling - commercial"
- "Gas" -> 1.401 -> "Losses"
- "Gas" -> 151.891 -> "Thermal generation"
- "Gas" -> 2.096 -> "Agriculture"
- "Gas" -> 48.58 -> "Industry"
- "Geothermal" -> 7.013 -> "Electricity grid"
- "H2 conversion" -> 20.897 -> "H2"
- "H2 conversion" -> 6.242 -> "Losses"
- "H2" -> 20.897 -> "Road transport"
- "Hydro" -> 6.995 -> "Electricity grid"
- "Liquid" -> 121.066 -> "Industry"
- "Liquid" -> 128.69 -> "International shipping"
- "Liquid" -> 135.835 -> "Road transport"
- "Liquid" -> 14.458 -> "Domestic aviation"
- "Liquid" -> 206.267 -> "International aviation"
- "Liquid" -> 3.64 -> "Agriculture"
- "Liquid" -> 33.218 -> "National navigation"
- "Liquid" -> 4.413 -> "Rail transport"
- "Marine algae" -> 4.375 -> "Bio-conversion"
- "Ngas" -> 122.952 -> "Gas"
- "Nuclear" -> 839.978 -> "Thermal generation"
- "Oil imports" -> 504.287 -> "Oil"
- "Oil reserves" -> 107.703 -> "Oil"
- "Oil" -> 611.99 -> "Liquid"
- "Other waste" -> 56.587 -> "Solid"
- "Other waste" -> 77.81 -> "Bio-conversion"
- "Pumped heat" -> 193.026 -> "Heating and cooling - homes"
- "Pumped heat" -> 70.672 -> "Heating and cooling - commercial"
- "Solar PV" -> 59.901 -> "Electricity grid"
- "Solar Thermal" -> 19.263 -> "Heating and cooling - homes"
- "Solar" -> 19.263 -> "Solar Thermal"
- "Solar" -> 59.901 -> "Solar PV"
- "Solid" -> 0.882 -> "Agriculture"
- "Solid" -> 400.12 -> "Thermal generation"
- "Solid" -> 46.477 -> "Industry"
- "Thermal generation" -> 525.531 -> "Electricity grid"
- "Thermal generation" -> 787.129 -> "Losses"
- "Thermal generation" -> 79.329 -> "District heating"
- "Tidal" -> 9.452 -> "Electricity grid"
- "UK land based bioenergy" -> 182.01 -> "Bio-conversion"
- "Wave" -> 19.013 -> "Electricity grid"
- "Wind" -> 289.366 -> "Electricity grid"
+Agricultural 'waste',Bio-conversion,124.729
+Bio-conversion,Liquid,0.597
+Bio-conversion,Losses,26.862
+Bio-conversion,Solid,280.322
+Bio-conversion,Gas,81.144
+Biofuel imports,Liquid,35
+Biomass imports,Solid,35
+Coal imports,Coal,11.606
+Coal reserves,Coal,63.965
+Coal,Solid,75.571
+District heating,Industry,10.639
+District heating,Heating and cooling - commercial,22.505
+District heating,Heating and cooling - homes,46.184
+Electricity grid,Over generation / exports,104.453
+Electricity grid,Heating and cooling - homes,113.726
+Electricity grid,H2 conversion,27.14
+Electricity grid,Industry,342.165
+Electricity grid,Road transport,37.797
+Electricity grid,Agriculture,4.412
+Electricity grid,Heating and cooling - commercial,40.858
+Electricity grid,Losses,56.691
+Electricity grid,Rail transport,7.863
+Electricity grid,Lighting & appliances - commercial,90.008
+Electricity grid,Lighting & appliances - homes,93.494
+Gas imports,Ngas,40.719
+Gas reserves,Ngas,82.233
+Gas,Heating and cooling - commercial,0.129
+Gas,Losses,1.401
+Gas,Thermal generation,151.891
+Gas,Agriculture,2.096
+Gas,Industry,48.58
+Geothermal,Electricity grid,7.013
+H2 conversion,H2,20.897
+H2 conversion,Losses,6.242
+H2,Road transport,20.897
+Hydro,Electricity grid,6.995
+Liquid,Industry,121.066
+Liquid,International shipping,128.69
+Liquid,Road transport,135.835
+Liquid,Domestic aviation,14.458
+Liquid,International aviation,206.267
+Liquid,Agriculture,3.64
+Liquid,National navigation,33.218
+Liquid,Rail transport,4.413
+Marine algae,Bio-conversion,4.375
+Ngas,Gas,122.952
+Nuclear,Thermal generation,839.978
+Oil imports,Oil,504.287
+Oil reserves,Oil,107.703
+Oil,Liquid,611.99
+Other waste,Solid,56.587
+Other waste,Bio-conversion,77.81
+Pumped heat,Heating and cooling - homes,193.026
+Pumped heat,Heating and cooling - commercial,70.672
+Solar PV,Electricity grid,59.901
+Solar Thermal,Heating and cooling - homes,19.263
+Solar,Solar Thermal,19.263
+Solar,Solar PV,59.901
+Solid,Agriculture,0.882
+Solid,Thermal generation,400.12
+Solid,Industry,46.477
+Thermal generation,Electricity grid,525.531
+Thermal generation,Losses,787.129
+Thermal generation,District heating,79.329
+Tidal,Electricity grid,9.452
+UK land based bioenergy,Bio-conversion,182.01
+Wave,Electricity grid,19.013
+Wind,Electricity grid,289.366
diff --git a/packages/mermaid/src/diagrams/sankey/energy.csv b/packages/mermaid/src/diagrams/sankey/parser/energy.csv
similarity index 99%
rename from packages/mermaid/src/diagrams/sankey/energy.csv
rename to packages/mermaid/src/diagrams/sankey/parser/energy.csv
index e5691f66c..36fd45d2a 100644
--- a/packages/mermaid/src/diagrams/sankey/energy.csv
+++ b/packages/mermaid/src/diagrams/sankey/parser/energy.csv
@@ -1,4 +1,3 @@
-source,target,value
Agricultural 'waste',Bio-conversion,124.729
Bio-conversion,Liquid,0.597
Bio-conversion,Losses,26.862
diff --git a/packages/mermaid/src/diagrams/sankey/parser/sankey-arrow.jison b/packages/mermaid/src/diagrams/sankey/parser/sankey-arrow.jison
new file mode 100644
index 000000000..c981267a0
--- /dev/null
+++ b/packages/mermaid/src/diagrams/sankey/parser/sankey-arrow.jison
@@ -0,0 +1,105 @@
+/** mermaid */
+%lex
+TOKEN \w+
+NUM \d+(.\d+)?
+
+%options case-insensitive
+%options easy_keword_rules
+
+%s link_value
+
+%x attributes
+%x attr_value
+%x string
+
+%%
+//--------------------------------------------------------------
+// skip all whitespace EXCEPT newlines, but not within a string
+//--------------------------------------------------------------
+
+[^\S\r\n]+ {}
+
+//--------------
+// basic tokens
+//--------------
+
+(<>|[\n;])+ { return 'EOS'; } // end of statement is semicolon ; new line \n or end of file
+"sankey" { return 'SANKEY'; }
+{TOKEN} { return 'NODE_ID'; }
+{NUM} { return 'AMOUNT'; }
+"->" {
+ if(this.topState()!=='link_value') this.pushState('link_value');
+ else this.popState();
+ return 'ARROW';
+ }
+//------------
+// attributes
+//------------
+
+"[" { this.pushState('attributes'); return 'OPEN_ATTRIBUTES'; }
+"]" { this.popState(); return 'CLOSE_ATTRIBUTES'; }
+{TOKEN} { return 'ATTRIBUTE'; }
+\= { this.pushState('attr_value'); return 'EQUAL'; }
+{TOKEN} { this.popState(); return 'VALUE'; }
+
+//------------
+// strings
+//------------
+
+\" { this.pushState('string'); return 'OPEN_STRING'; }
+(?!\\)\" {
+ if(this.topState()==='string') this.popState();
+ if(this.topState()==='attr_value') this.popState();
+ return 'CLOSE_STRING';
+ }
+([^"\\]|\\\"|\\\\)+ { return 'STRING'; }
+
+/lex
+
+%start start
+%left ARROW
+
+%% // language grammar
+
+start
+ : EOS SANKEY document
+ | SANKEY document
+ ;
+
+document
+ : line document
+ |
+ ;
+
+line
+ : node optional_attributes EOS
+ | stream optional_attributes EOS
+ | EOS
+ ;
+
+optional_attributes: OPEN_ATTRIBUTES attributes CLOSE_ATTRIBUTES | ;
+
+attributes: attribute attributes | ;
+attribute: ATTRIBUTE EQUAL value | ATTRIBUTE;
+
+value: VALUE | OPEN_STRING STRING CLOSE_STRING;
+
+stream
+ : node\[source] ARROW amount ARROW tail\[target] {
+ $$=$source;
+ yy.addLink($source, $target, $amount);
+ }
+ ;
+
+tail
+ : stream { $$ = $stream }
+ | node { $$ = $node; }
+ ;
+
+amount: AMOUNT { $$=parseFloat($AMOUNT); };
+
+node
+ : NODE_ID { $$ = yy.findOrCreateNode($NODE_ID); }
+ | OPEN_STRING STRING\[node_label] CLOSE_STRING { $$ = yy.findOrCreateNode($node_label); }
+ ;
+
diff --git a/packages/mermaid/src/diagrams/sankey/parser/sankey.spec.js b/packages/mermaid/src/diagrams/sankey/parser/sankey-arrow.spec.js
similarity index 100%
rename from packages/mermaid/src/diagrams/sankey/parser/sankey.spec.js
rename to packages/mermaid/src/diagrams/sankey/parser/sankey-arrow.spec.js
diff --git a/packages/mermaid/src/diagrams/sankey/parser/sankey.jison b/packages/mermaid/src/diagrams/sankey/parser/sankey.jison
index c981267a0..5ad25e811 100644
--- a/packages/mermaid/src/diagrams/sankey/parser/sankey.jison
+++ b/packages/mermaid/src/diagrams/sankey/parser/sankey.jison
@@ -1,105 +1,82 @@
/** mermaid */
+
+//----------------------------------------------------
+// We support csv format as defined there
+// CSV format // https://www.ietf.org/rfc/rfc4180.txt
+//----------------------------------------------------
+
%lex
-TOKEN \w+
-NUM \d+(.\d+)?
%options case-insensitive
%options easy_keword_rules
-%s link_value
-
-%x attributes
-%x attr_value
-%x string
+// as per section 6.1 of RFC 2234 [2]
+COMMA \u002C
+CR \u000D
+LF \u000A
+CRLF \u000D\u000A
+DQUOTE \u0022
+TEXTDATA [\u0020-\u0021\u0023-\u002B\u002D-\u007E]
%%
-//--------------------------------------------------------------
-// skip all whitespace EXCEPT newlines, but not within a string
-//--------------------------------------------------------------
-[^\S\r\n]+ {}
+<> { return 'EOF' }
-//--------------
-// basic tokens
-//--------------
-
-(<>|[\n;])+ { return 'EOS'; } // end of statement is semicolon ; new line \n or end of file
-"sankey" { return 'SANKEY'; }
-{TOKEN} { return 'NODE_ID'; }
-{NUM} { return 'AMOUNT'; }
-"->" {
- if(this.topState()!=='link_value') this.pushState('link_value');
- else this.popState();
- return 'ARROW';
- }
-//------------
-// attributes
-//------------
-
-"[" { this.pushState('attributes'); return 'OPEN_ATTRIBUTES'; }
-"]" { this.popState(); return 'CLOSE_ATTRIBUTES'; }
-{TOKEN} { return 'ATTRIBUTE'; }
-\= { this.pushState('attr_value'); return 'EQUAL'; }
-{TOKEN} { this.popState(); return 'VALUE'; }
-
-//------------
-// strings
-//------------
-
-\" { this.pushState('string'); return 'OPEN_STRING'; }
-(?!\\)\" {
- if(this.topState()==='string') this.popState();
- if(this.topState()==='attr_value') this.popState();
- return 'CLOSE_STRING';
- }
-([^"\\]|\\\"|\\\\)+ { return 'STRING'; }
+"sankey" { return 'SANKEY' }
+{COMMA} { return 'COMMA' }
+{DQUOTE} { return 'DQUOTE' }
+({CRLF}|{LF}) { return 'NEWLINE' }
+{TEXTDATA}* { return 'NON_ESCAPED_TEXT' }
+({TEXTDATA}|{COMMA}|{CR}|{LF}|{DQUOTE}{DQUOTE})* { return 'ESCAPED_TEXT' }
/lex
%start start
-%left ARROW
%% // language grammar
start
- : EOS SANKEY document
- | SANKEY document
+ : SANKEY file opt_eof
;
-document
- : line document
- |
+file: csv opt_newline;
+
+csv
+ : record csv_tail
;
-line
- : node optional_attributes EOS
- | stream optional_attributes EOS
- | EOS
+csv_tail
+ : NEWLINE csv
+ | // empty
;
-optional_attributes: OPEN_ATTRIBUTES attributes CLOSE_ATTRIBUTES | ;
-
-attributes: attribute attributes | ;
-attribute: ATTRIBUTE EQUAL value | ATTRIBUTE;
-
-value: VALUE | OPEN_STRING STRING CLOSE_STRING;
-
-stream
- : node\[source] ARROW amount ARROW tail\[target] {
- $$=$source;
- yy.addLink($source, $target, $amount);
- }
+opt_newline
+ : NEWLINE
+ | // empty
;
-tail
- : stream { $$ = $stream }
- | node { $$ = $node; }
- ;
-
-amount: AMOUNT { $$=parseFloat($AMOUNT); };
-
-node
- : NODE_ID { $$ = yy.findOrCreateNode($NODE_ID); }
- | OPEN_STRING STRING\[node_label] CLOSE_STRING { $$ = yy.findOrCreateNode($node_label); }
+opt_eof
+ : EOF
+ | // empty
;
+record
+ : field\[source] COMMA field\[target] COMMA field\[value] {
+ const source = yy.findOrCreateNode($source);
+ const target = yy.findOrCreateNode($target);
+ const value = parseFloat($value);
+ $$ = yy.addLink(source,target,value);
+ } // parse only 3 fields, this is not part of standard
+ | // allow empty record to handle empty lines, this is not part of csv standard either
+ ;
+
+field
+ : escaped { $$=$escaped; }
+ | non_escaped { $$=$non_escaped; }
+ ;
+
+escaped: DQUOTE ESCAPED_TEXT DQUOTE { $$=$ESCAPED_TEXT; };
+
+non_escaped: NON_ESCAPED_TEXT { $$=$NON_ESCAPED_TEXT; };
+
+
diff --git a/packages/mermaid/src/diagrams/sankey/parser/sankey.spec.ts b/packages/mermaid/src/diagrams/sankey/parser/sankey.spec.ts
new file mode 100644
index 000000000..0c83df33f
--- /dev/null
+++ b/packages/mermaid/src/diagrams/sankey/parser/sankey.spec.ts
@@ -0,0 +1,33 @@
+// @ts-ignore: jison doesn't export types
+import diagram from './sankey.jison';
+// @ts-ignore: jison doesn't export types
+import { parser } from './sankey.jison';
+import db from '../sankeyDB.js';
+// import { fail } from 'assert';
+
+
+describe('Sankey diagram', function () {
+ // TODO - these examples should be put into ./parser/stateDiagram.spec.js
+ describe('when parsing an info graph it', function () {
+ beforeEach(function () {
+ parser.yy = db;
+ diagram.parser.yy = db;
+ diagram.parser.yy.clear();
+ });
+
+ it('parses csv', async () => {
+
+ const fs = require('fs');
+ const path = require('path').resolve(__dirname, "./energy.csv");
+ await fs.readFile(path, 'utf8', (err: Error, data: string) => {
+ if (err) throw(err);
+
+ const str = `sankey\\n${data}`;
+
+ parser.parse(str);
+ });
+
+ });
+
+ });
+});