Skip to content

Commit 7ca02da

Browse files
committed
feat: create sankey parser and integrate sankey parser into mermaid package
1 parent 44b93c0 commit 7ca02da

28 files changed

+900
-317
lines changed

__mocks__/sankeyRenderer.js

-13
This file was deleted.

__mocks__/sankeyRenderer.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Mocked Sankey diagram renderer
3+
*/
4+
import { vi } from 'vitest';
5+
6+
export const draw = vi.fn().mockImplementation(() => undefined);
7+
8+
export const renderer = { draw };

packages/mermaid/src/diagram-api/diagram-orchestration.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
1818
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
1919
import timeline from '../diagrams/timeline/detector.js';
2020
import mindmap from '../diagrams/mindmap/detector.js';
21-
import sankey from '../diagrams/sankey/sankeyDetector.js';
21+
import { sankey } from '../diagrams/sankey/sankeyDetector.js';
2222
import { registerLazyLoadedDiagrams } from './detectType.js';
2323
import { registerDiagram } from './diagramAPI.js';
2424

packages/mermaid/src/diagrams/sankey/parser/sankey.jison

-69
This file was deleted.

packages/mermaid/src/diagrams/sankey/parser/sankey.spec.ts

-24
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { parser } from './sankeyParser.js';
2+
import { db } from './sankeyDB.js';
3+
import * as fs from 'fs';
4+
import * as path from 'path';
5+
6+
describe('sankey', () => {
7+
beforeEach(() => db.clear());
8+
9+
it('should parse csv', () => {
10+
const csv = path.resolve(__dirname, './parser/energy.csv');
11+
const data = fs.readFileSync(csv, 'utf8');
12+
const graphDefinition = 'sankey-beta\n\n ' + data;
13+
14+
parser.parse(graphDefinition);
15+
});
16+
});
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as configApi from '../../config.js';
2-
import common from '../common/common.js';
31
import {
42
setAccTitle,
53
getAccTitle,
@@ -9,73 +7,63 @@ import {
97
getDiagramTitle,
108
clear as commonClear,
119
} from '../../commonDb.js';
10+
import type { SankeyDiagramConfig } from '../../config.type.js';
11+
import type { SankeyDB, SankeyLink as ISankeyLink, SankeyFields } from './sankeyTypes.js';
12+
import DEFAULT_CONFIG from '../../defaultConfig.js';
13+
import type { RequiredDeep } from 'type-fest';
14+
15+
export const DEFAULT_SANKEY_CONFIG: Required<SankeyDiagramConfig> = DEFAULT_CONFIG.sankey;
16+
17+
export const DEFAULT_SANKEY_DB: RequiredDeep<SankeyFields> = {
18+
links: [] as ISankeyLink[],
19+
nodes: [] as string[],
20+
config: DEFAULT_SANKEY_CONFIG,
21+
} as const;
1222

1323
// Sankey diagram represented by nodes and links between those nodes
14-
let links: SankeyLink[] = [];
24+
let links: ISankeyLink[] = DEFAULT_SANKEY_DB.links;
1525
// Array of nodes guarantees their order
16-
let nodes: SankeyNode[] = [];
17-
// We also have to track nodes uniqueness (by ID)
18-
let nodesMap: Record<string, SankeyNode> = {};
26+
let nodes: string[] = DEFAULT_SANKEY_DB.nodes;
27+
const config: Required<SankeyDiagramConfig> = structuredClone(DEFAULT_SANKEY_CONFIG);
28+
29+
const getConfig = (): Required<SankeyDiagramConfig> => structuredClone(config);
1930

2031
const clear = (): void => {
2132
links = [];
2233
nodes = [];
23-
nodesMap = {};
2434
commonClear();
2535
};
2636

27-
class SankeyLink {
28-
constructor(public source: SankeyNode, public target: SankeyNode, public value: number = 0) {}
29-
}
30-
3137
/**
3238
* @param source - Node where the link starts
3339
* @param target - Node where the link ends
3440
* @param value - Describes the amount to be passed
3541
*/
36-
const addLink = (source: SankeyNode, target: SankeyNode, value: number): void => {
37-
links.push(new SankeyLink(source, target, value));
42+
const addLink = ({ source, target, value }: ISankeyLink): void => {
43+
links.push({ source, target, value });
3844
};
3945

40-
class SankeyNode {
41-
constructor(public ID: string) {}
42-
}
43-
44-
const findOrCreateNode = (ID: string): SankeyNode => {
45-
ID = common.sanitizeText(ID, configApi.getConfig());
46+
const getLinks = (): ISankeyLink[] => links;
4647

47-
if (!nodesMap[ID]) {
48-
nodesMap[ID] = new SankeyNode(ID);
49-
nodes.push(nodesMap[ID]);
50-
}
51-
return nodesMap[ID];
48+
const addNode = (node: string): void => {
49+
nodes.push(node);
5250
};
5351

54-
const getNodes = () => nodes;
55-
const getLinks = () => links;
52+
const getNodes = (): string[] => nodes;
5653

57-
const getGraph = () => ({
58-
nodes: nodes.map((node) => ({ id: node.ID })),
59-
links: links.map((link) => ({
60-
source: link.source.ID,
61-
target: link.target.ID,
62-
value: link.value,
63-
})),
64-
});
54+
export const db: SankeyDB = {
55+
getConfig,
6556

66-
export default {
67-
nodesMap,
68-
getConfig: () => configApi.getConfig().sankey,
69-
getNodes,
70-
getLinks,
71-
getGraph,
72-
addLink,
73-
findOrCreateNode,
74-
getAccTitle,
57+
clear,
58+
setDiagramTitle,
59+
getDiagramTitle,
7560
setAccTitle,
76-
getAccDescription,
61+
getAccTitle,
7762
setAccDescription,
78-
getDiagramTitle,
79-
setDiagramTitle,
80-
clear,
63+
getAccDescription,
64+
65+
addLink,
66+
addNode,
67+
getLinks,
68+
getNodes,
8169
};

packages/mermaid/src/diagrams/sankey/sankeyDetector.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
1+
import type {
2+
DiagramDetector,
3+
DiagramLoader,
4+
ExternalDiagramDefinition,
5+
} from '../../diagram-api/types.js';
26

37
const id = 'sankey';
48

59
const detector: DiagramDetector = (txt) => {
610
return /^\s*sankey-beta/.test(txt);
711
};
812

9-
const loader = async () => {
13+
const loader: DiagramLoader = async () => {
1014
const { diagram } = await import('./sankeyDiagram.js');
1115
return { id, diagram };
1216
};
1317

14-
const plugin: ExternalDiagramDefinition = {
18+
export const sankey: ExternalDiagramDefinition = {
1519
id,
1620
detector,
1721
loader,
1822
};
19-
20-
export default plugin;

packages/mermaid/src/diagrams/sankey/sankeyDiagram.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import type { DiagramDefinition } from '../../diagram-api/types.js';
2-
// @ts-ignore: jison doesn't export types
3-
import parser from './parser/sankey.jison';
4-
import db from './sankeyDB.js';
5-
import renderer from './sankeyRenderer.js';
6-
import { prepareTextForParsing } from './sankeyUtils.js';
7-
8-
const originalParse = parser.parse.bind(parser);
9-
parser.parse = (text: string) => originalParse(prepareTextForParsing(text));
2+
import { parser } from './sankeyParser.js';
3+
import { db } from './sankeyDB.js';
4+
import { renderer } from './sankeyRenderer.js';
105

116
export const diagram: DiagramDefinition = {
127
parser,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Sankey, SankeyLink } from 'mermaid-parser';
2+
import { parse } from 'mermaid-parser';
3+
4+
import { log } from '../../logger.js';
5+
import type { ParserDefinition } from '../../diagram-api/types.js';
6+
import { populateCommonDb } from '../common/populateCommonDb.js';
7+
import type { SankeyDB } from './sankeyTypes.js';
8+
import { db } from './sankeyDB.js';
9+
10+
function populateDb(ast: Sankey, db: SankeyDB) {
11+
populateCommonDb(ast, db);
12+
ast.links.forEach((link: SankeyLink) => {
13+
db.addLink(link);
14+
});
15+
ast.nodes.forEach((node: string) => {
16+
db.addNode(node);
17+
});
18+
}
19+
20+
export const parser: ParserDefinition = {
21+
parse: (input: string): void => {
22+
const ast: Sankey = parse('sankey', input);
23+
log.debug(ast);
24+
populateDb(ast, db);
25+
},
26+
};

0 commit comments

Comments
 (0)