Skip to content

Commit

Permalink
feat: create sankey parser and integrate sankey parser into `merm…
Browse files Browse the repository at this point in the history
…aid` package
  • Loading branch information
Yokozuna59 committed Sep 2, 2023
1 parent 44b93c0 commit a5b0590
Show file tree
Hide file tree
Showing 26 changed files with 905 additions and 304 deletions.
2 changes: 1 addition & 1 deletion packages/mermaid/src/diagram-api/diagram-orchestration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
import timeline from '../diagrams/timeline/detector.js';
import mindmap from '../diagrams/mindmap/detector.js';
import sankey from '../diagrams/sankey/sankeyDetector.js';
import { sankey } from '../diagrams/sankey/sankeyDetector.js';
import { registerLazyLoadedDiagrams } from './detectType.js';
import { registerDiagram } from './diagramAPI.js';

Expand Down
69 changes: 0 additions & 69 deletions packages/mermaid/src/diagrams/sankey/parser/sankey.jison

This file was deleted.

24 changes: 0 additions & 24 deletions packages/mermaid/src/diagrams/sankey/parser/sankey.spec.ts

This file was deleted.

16 changes: 16 additions & 0 deletions packages/mermaid/src/diagrams/sankey/sankey.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { parser } from './sankeyParser.js';
import { db } from './sankeyDB.js';
import * as fs from 'fs';
import * as path from 'path';

describe('sankey', () => {
beforeEach(() => db.clear());

it('should parse csv', () => {
const csv = path.resolve(__dirname, './parser/energy.csv');
const data = fs.readFileSync(csv, 'utf8');
const graphDefinition = 'sankey-beta\n\n ' + data;

parser.parse(graphDefinition);
});
});
94 changes: 47 additions & 47 deletions packages/mermaid/src/diagrams/sankey/sankeyDB.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as configApi from '../../config.js';
import common from '../common/common.js';
import {
setAccTitle,
getAccTitle,
Expand All @@ -9,73 +7,75 @@ import {
getDiagramTitle,
clear as commonClear,
} from '../../commonDb.js';
import type { SankeyDiagramConfig } from '../../config.type.js';
import type { SankeyDB, SankeyLink as ISankeyLink, SankeyFields } from './sankeyTypes.js';
import DEFAULT_CONFIG from '../../defaultConfig.js';
import type { RequiredDeep } from 'type-fest';

export const DEFAULT_SANKEY_CONFIG: Required<SankeyDiagramConfig> = DEFAULT_CONFIG.sankey;

export const DEFAULT_SANKEY_DB: RequiredDeep<SankeyFields> = {
links: [] as ISankeyLink[],
nodes: [] as string[],
config: DEFAULT_SANKEY_CONFIG,
} as const;

// Sankey diagram represented by nodes and links between those nodes
let links: SankeyLink[] = [];
let links: ISankeyLink[] = DEFAULT_SANKEY_DB.links;
// Array of nodes guarantees their order
let nodes: SankeyNode[] = [];
// We also have to track nodes uniqueness (by ID)
let nodesMap: Record<string, SankeyNode> = {};
let nodes: string[] = DEFAULT_SANKEY_DB.nodes;
const config: Required<SankeyDiagramConfig> = structuredClone(DEFAULT_SANKEY_CONFIG);

const getConfig = (): Required<SankeyDiagramConfig> => {
return {
...structuredClone(config),
width: 600,
height: 400,
linkColor: 'gradient',
nodeAlignment: 'justify',
useMaxWidth: true,
showValues: true,
prefix: '',
suffix: '',
};
};

const clear = (): void => {
links = [];
nodes = [];
nodesMap = {};
commonClear();
};

class SankeyLink {
constructor(public source: SankeyNode, public target: SankeyNode, public value: number = 0) {}
}

/**
* @param source - Node where the link starts
* @param target - Node where the link ends
* @param value - Describes the amount to be passed
*/
const addLink = (source: SankeyNode, target: SankeyNode, value: number): void => {
links.push(new SankeyLink(source, target, value));
const addLink = ({ source, target, value }: ISankeyLink): void => {
links.push({ source, target, value });
};

class SankeyNode {
constructor(public ID: string) {}
}

const findOrCreateNode = (ID: string): SankeyNode => {
ID = common.sanitizeText(ID, configApi.getConfig());
const getLinks = (): ISankeyLink[] => links;

if (!nodesMap[ID]) {
nodesMap[ID] = new SankeyNode(ID);
nodes.push(nodesMap[ID]);
}
return nodesMap[ID];
const addNode = (node: string): void => {
nodes.push(node);
};

const getNodes = () => nodes;
const getLinks = () => links;
const getNodes = (): string[] => nodes;

const getGraph = () => ({
nodes: nodes.map((node) => ({ id: node.ID })),
links: links.map((link) => ({
source: link.source.ID,
target: link.target.ID,
value: link.value,
})),
});
export const db: SankeyDB = {
getConfig,

export default {
nodesMap,
getConfig: () => configApi.getConfig().sankey,
getNodes,
getLinks,
getGraph,
addLink,
findOrCreateNode,
getAccTitle,
clear,
setDiagramTitle,
getDiagramTitle,
setAccTitle,
getAccDescription,
getAccTitle,
setAccDescription,
getDiagramTitle,
setDiagramTitle,
clear,
getAccDescription,

addLink,
addNode,
getLinks,
getNodes,
};
12 changes: 7 additions & 5 deletions packages/mermaid/src/diagrams/sankey/sankeyDetector.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
import type {
DiagramDetector,
DiagramLoader,
ExternalDiagramDefinition,
} from '../../diagram-api/types.js';

const id = 'sankey';

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

const loader = async () => {
const loader: DiagramLoader = async () => {
const { diagram } = await import('./sankeyDiagram.js');
return { id, diagram };
};

const plugin: ExternalDiagramDefinition = {
export const sankey: ExternalDiagramDefinition = {
id,
detector,
loader,
};

export default plugin;
11 changes: 3 additions & 8 deletions packages/mermaid/src/diagrams/sankey/sankeyDiagram.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import type { DiagramDefinition } from '../../diagram-api/types.js';
// @ts-ignore: jison doesn't export types
import parser from './parser/sankey.jison';
import db from './sankeyDB.js';
import renderer from './sankeyRenderer.js';
import { prepareTextForParsing } from './sankeyUtils.js';

const originalParse = parser.parse.bind(parser);
parser.parse = (text: string) => originalParse(prepareTextForParsing(text));
import { parser } from './sankeyParser.js';
import { db } from './sankeyDB.js';
import { renderer } from './sankeyRenderer.js';

export const diagram: DiagramDefinition = {
parser,
Expand Down
26 changes: 26 additions & 0 deletions packages/mermaid/src/diagrams/sankey/sankeyParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Sankey, SankeyLink } from 'mermaid-parser';
import { parse } from 'mermaid-parser';

import { log } from '../../logger.js';
import type { ParserDefinition } from '../../diagram-api/types.js';
import { populateCommonDb } from '../common/populateCommonDb.js';
import type { SankeyDB } from './sankeyTypes.js';
import { db } from './sankeyDB.js';

function populateDb(ast: Sankey, db: SankeyDB) {
populateCommonDb(ast, db);
ast.links.forEach((link: SankeyLink) => {
db.addLink(link);
});
ast.nodes.forEach((node: string) => {
db.addNode(node);
});
}

export const parser: ParserDefinition = {
parse: (input: string): void => {
const ast: Sankey = parse('sankey', input);
log.debug(ast);
populateDb(ast, db);
},
};
Loading

0 comments on commit a5b0590

Please sign in to comment.