3.9 KB98 lines
Blame
1import type { LangiumParser, ParseResult } from 'langium';
2
3import type { Info, Packet, Pie, Architecture, GitGraph, Radar, Treemap } from './index.js';
4
5export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar;
6
7const parsers: Record<string, LangiumParser> = {};
8const initializers = {
9 info: async () => {
10 const { createInfoServices } = await import('./language/info/index.js');
11 const parser = createInfoServices().Info.parser.LangiumParser;
12 parsers.info = parser;
13 },
14 packet: async () => {
15 const { createPacketServices } = await import('./language/packet/index.js');
16 const parser = createPacketServices().Packet.parser.LangiumParser;
17 parsers.packet = parser;
18 },
19 pie: async () => {
20 const { createPieServices } = await import('./language/pie/index.js');
21 const parser = createPieServices().Pie.parser.LangiumParser;
22 parsers.pie = parser;
23 },
24 architecture: async () => {
25 const { createArchitectureServices } = await import('./language/architecture/index.js');
26 const parser = createArchitectureServices().Architecture.parser.LangiumParser;
27 parsers.architecture = parser;
28 },
29 gitGraph: async () => {
30 const { createGitGraphServices } = await import('./language/gitGraph/index.js');
31 const parser = createGitGraphServices().GitGraph.parser.LangiumParser;
32 parsers.gitGraph = parser;
33 },
34 radar: async () => {
35 const { createRadarServices } = await import('./language/radar/index.js');
36 const parser = createRadarServices().Radar.parser.LangiumParser;
37 parsers.radar = parser;
38 },
39 treemap: async () => {
40 const { createTreemapServices } = await import('./language/treemap/index.js');
41 const parser = createTreemapServices().Treemap.parser.LangiumParser;
42 parsers.treemap = parser;
43 },
44} as const;
45
46export async function parse(diagramType: 'info', text: string): Promise<Info>;
47export async function parse(diagramType: 'packet', text: string): Promise<Packet>;
48export async function parse(diagramType: 'pie', text: string): Promise<Pie>;
49export async function parse(diagramType: 'architecture', text: string): Promise<Architecture>;
50export async function parse(diagramType: 'gitGraph', text: string): Promise<GitGraph>;
51export async function parse(diagramType: 'radar', text: string): Promise<Radar>;
52export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>;
53
54export async function parse<T extends DiagramAST>(
55 diagramType: keyof typeof initializers,
56 text: string
57): Promise<T> {
58 const initializer = initializers[diagramType];
59 if (!initializer) {
60 throw new Error(`Unknown diagram type: ${diagramType}`);
61 }
62 if (!parsers[diagramType]) {
63 await initializer();
64 }
65 const parser: LangiumParser = parsers[diagramType];
66 const result: ParseResult<T> = parser.parse<T>(text);
67 if (result.lexerErrors.length > 0 || result.parserErrors.length > 0) {
68 throw new MermaidParseError(result);
69 }
70 return result.value;
71}
72
73export class MermaidParseError extends Error {
74 constructor(public result: ParseResult<DiagramAST>) {
75 const lexerErrors: string = result.lexerErrors
76 .map((err) => {
77 const line = err.line !== undefined && !isNaN(err.line) ? err.line : '?';
78 const column = err.column !== undefined && !isNaN(err.column) ? err.column : '?';
79 return `Lexer error on line ${line}, column ${column}: ${err.message}`;
80 })
81 .join('\n');
82 const parserErrors: string = result.parserErrors
83 .map((err) => {
84 const line =
85 err.token.startLine !== undefined && !isNaN(err.token.startLine)
86 ? err.token.startLine
87 : '?';
88 const column =
89 err.token.startColumn !== undefined && !isNaN(err.token.startColumn)
90 ? err.token.startColumn
91 : '?';
92 return `Parse error on line ${line}, column ${column}: ${err.message}`;
93 })
94 .join('\n');
95 super(`Parsing failed: ${lexerErrors} ${parserErrors}`);
96 }
97}
98