Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create sankey parser and integrate sankey parser into mermaid package #4799

Open
wants to merge 35 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7ca02da
feat: create `sankey` parser and integrate `sankey` parser into `merm…
Yokozuna59 Sep 2, 2023
a10821f
chore: remove sankey links map
Yokozuna59 Sep 2, 2023
9ad5536
chore: remove sankey links map
Yokozuna59 Sep 2, 2023
9a8963a
Merge branch 'next' into add-sankey-langium-parser
Yokozuna59 Sep 2, 2023
8feef1e
chore: `vi.mock` sankey renderer
Yokozuna59 Sep 2, 2023
efbb1f1
styles: refactor `switch..case` into `Record` for matcher regexes
Yokozuna59 Sep 2, 2023
b6906a6
fix: match until comments in `sankey` diagram
Yokozuna59 Sep 2, 2023
8c40eb3
Merge branch next into add-sankey-langium-parser
Yokozuna59 Sep 20, 2023
63430d2
pref(sankey): combine `source` and `target` rules as `node`
Yokozuna59 Sep 20, 2023
5fe951a
chore: update rule name of why we can't use default import in sankey
Yokozuna59 Sep 20, 2023
6187f4b
change test case with double quotes values
Yokozuna59 Sep 20, 2023
709ece5
Merge branch 'next' into add-sankey-langium-parser
Yokozuna59 Feb 12, 2024
aa9e875
update pnpm-lock.yaml
Yokozuna59 Feb 12, 2024
15c8bf8
update sankey parser tests
Yokozuna59 Feb 12, 2024
c364715
update the parser `index.ts` exports
Yokozuna59 Feb 12, 2024
32d82a6
add the approach from #4910 pr
Yokozuna59 Feb 12, 2024
bb84e17
change ISankeyLink into SankeyLink in sankeyDB
Yokozuna59 Feb 12, 2024
e51b7a4
modify sankye matcher
Yokozuna59 Feb 12, 2024
eb55e39
rename sankey langium parser files
Yokozuna59 Feb 12, 2024
4d035ed
simplify `sankey.langium`
Yokozuna59 Feb 13, 2024
56c643d
use `AbstractMermaidTokenBuilder` in sankey token builder
Yokozuna59 Feb 13, 2024
c0535f4
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Mar 24, 2024
0705aff
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Mar 24, 2024
bf95a30
fix lint:fix
Yokozuna59 Mar 24, 2024
434d154
remove unused imports
Yokozuna59 Mar 24, 2024
6c7b0f2
implement the greedy annotation approach
Yokozuna59 Mar 26, 2024
125ec46
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Mar 26, 2024
c9f6816
apply review suggestions
Yokozuna59 Mar 26, 2024
c155434
remove `utils.ts` and related unused imports
Yokozuna59 Apr 14, 2024
3597ffe
reorder sankey.langium rules
Yokozuna59 Apr 14, 2024
e080e96
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Apr 14, 2024
875c4fe
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Apr 15, 2024
51896f3
create separate test case for `CommonTokenBuilder`
Yokozuna59 Apr 15, 2024
8fa0509
run fix lint
Yokozuna59 Apr 15, 2024
681fbd0
Merge branch 'develop' into add-sankey-langium-parser
Yokozuna59 Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions __mocks__/sankeyRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Mocked Sankey diagram renderer
*/
import { vi } from 'vitest';

export const draw = vi.fn().mockImplementation(() => undefined);

export const renderer = { draw };
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 @@ -19,7 +19,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 { packet } from '../diagrams/packet/detector.js';
import block from '../diagrams/block/blockDetector.js';
import { registerLazyLoadedDiagrams } from './detectType.js';
Expand Down
66 changes: 0 additions & 66 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', async () => {
const csv = path.resolve(__dirname, './parser/energy.csv');
const data = fs.readFileSync(csv, 'utf8');
const graphDefinition = 'sankey-beta\n\n ' + data;

await parser.parse(graphDefinition);
});
});
86 changes: 35 additions & 51 deletions packages/mermaid/src/diagrams/sankey/sankeyDB.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { getConfig } from '../../diagram-api/diagramAPI.js';
import common from '../common/common.js';
import {
setAccTitle,
getAccTitle,
Expand All @@ -9,77 +7,63 @@ import {
getDiagramTitle,
clear as commonClear,
} from '../common/commonDb.js';
import type { SankeyDiagramConfig } from '../../config.type.js';
import type { SankeyDB, SankeyLink, 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 SankeyLink[],
nodes: [] as string[],
config: DEFAULT_SANKEY_CONFIG,
} as const;

// Sankey diagram represented by nodes and links between those nodes
let links: SankeyLink[] = [];
let links: SankeyLink[] = 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> => structuredClone(config);

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 }: SankeyLink): void => {
links.push({ source, target, value });
};

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

const findOrCreateNode = (ID: string): SankeyNode => {
ID = common.sanitizeText(ID, getConfig());
const getLinks = (): SankeyLink[] => 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,
clear,

export default {
nodesMap,
getConfig: () => getConfig().sankey,
getNodes,
getLinks,
getGraph,
addLink,
findOrCreateNode,
getAccTitle,
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-js/parser';
import { parse } from '@mermaid-js/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: async (input: string): Promise<void> => {
const ast: Sankey = await parse('sankey', input);
log.debug(ast);
populateDb(ast, db);
},
};
Loading
Loading