| 1 | import type { LangiumParser, ParseResult } from 'langium'; |
| 2 | |
| 3 | import type { Info, Packet, Pie, Architecture, GitGraph, Radar, Treemap } from './index.js'; |
| 4 | |
| 5 | export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar; |
| 6 | |
| 7 | const parsers: Record<string, LangiumParser> = {}; |
| 8 | const 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 | |
| 46 | export async function parse(diagramType: 'info', text: string): Promise<Info>; |
| 47 | export async function parse(diagramType: 'packet', text: string): Promise<Packet>; |
| 48 | export async function parse(diagramType: 'pie', text: string): Promise<Pie>; |
| 49 | export async function parse(diagramType: 'architecture', text: string): Promise<Architecture>; |
| 50 | export async function parse(diagramType: 'gitGraph', text: string): Promise<GitGraph>; |
| 51 | export async function parse(diagramType: 'radar', text: string): Promise<Radar>; |
| 52 | export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>; |
| 53 | |
| 54 | export 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 | |
| 73 | export 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 | |