mermaid
Version:
Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.
5 lines • 59.8 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/diagrams/railroad/railroadDb.ts", "../../../src/diagrams/railroad/railroadTypes.ts", "../../../src/diagrams/railroad/styles.ts", "../../../src/diagrams/railroad/railroadRenderer.ts"],
"sourcesContent": ["import type { ASTNode, RailroadDB, RailroadRule } from './railroadTypes.js';\nimport { getConfig as getGlobalConfig } from '../../diagram-api/diagramAPI.js';\nimport { log } from '../../logger.js';\nimport { clear as commonClear } from '../common/commonDb.js';\nimport { sanitizeText as commonSanitizeText } from '../common/common.js';\n\nlet diagramTitle = '';\nlet accTitle = '';\nlet accDescription = '';\nconst rules: RailroadRule[] = [];\nconst ruleMap = new Map<string, RailroadRule>();\n\nconst sanitizeText = (text: string): string => {\n return commonSanitizeText(text, getGlobalConfig());\n};\n\nconst sanitizeAstNode = (node: ASTNode): ASTNode => {\n switch (node.type) {\n case 'terminal':\n return { ...node, value: sanitizeText(node.value) };\n case 'nonterminal':\n return { ...node, name: sanitizeText(node.name) };\n case 'sequence':\n return { ...node, elements: node.elements.map(sanitizeAstNode) };\n case 'choice':\n return { ...node, alternatives: node.alternatives.map(sanitizeAstNode) };\n case 'optional':\n return { ...node, element: sanitizeAstNode(node.element) };\n case 'repetition':\n return {\n ...node,\n element: sanitizeAstNode(node.element),\n separator: node.separator ? sanitizeAstNode(node.separator) : undefined,\n };\n case 'special':\n return { ...node, text: sanitizeText(node.text) };\n }\n};\n\n/**\n * Clear all diagram state\n */\nconst clear = (): void => {\n diagramTitle = '';\n accTitle = '';\n accDescription = '';\n rules.length = 0;\n ruleMap.clear();\n commonClear();\n log.debug('[Railroad] Database cleared');\n};\n\n/**\n * Set diagram title\n */\nconst setTitle = (text: string): void => {\n diagramTitle = sanitizeText(text);\n log.debug('[Railroad] Title set:', text);\n};\n\n/**\n * Get diagram title\n */\nconst getTitle = (): string => {\n return diagramTitle;\n};\n\n/**\n * Add a new rule to the diagram\n */\nconst addRule = (rule: RailroadRule): void => {\n const sanitizedRule: RailroadRule = {\n ...rule,\n name: sanitizeText(rule.name),\n definition: sanitizeAstNode(rule.definition),\n comment: rule.comment ? sanitizeText(rule.comment) : undefined,\n };\n\n log.debug('[Railroad] Adding rule:', sanitizedRule.name);\n\n // Check for duplicate rule names\n if (ruleMap.has(sanitizedRule.name)) {\n log.warn(`[Railroad] Rule '${sanitizedRule.name}' is already defined. Overwriting.`);\n }\n\n rules.push(sanitizedRule);\n ruleMap.set(sanitizedRule.name, sanitizedRule);\n};\n\n/**\n * Get all rules\n */\nconst getRules = (): RailroadRule[] => {\n return rules;\n};\n\n/**\n * Get a specific rule by name\n */\nconst getRule = (name: string): RailroadRule | undefined => {\n return ruleMap.get(name);\n};\n\n/**\n * Set accessibility title\n */\nconst setAccTitle = (text: string): void => {\n accTitle = sanitizeText(text).replace(/^\\s+/g, '');\n log.debug('[Railroad] Accessibility title set:', text);\n};\n\n/**\n * Get accessibility title\n */\nconst getAccTitle = (): string => {\n return accTitle;\n};\n\n/**\n * Set accessibility description\n */\nconst setAccDescription = (text: string): void => {\n accDescription = sanitizeText(text).replace(/\\n\\s+/g, '\\n');\n log.debug('[Railroad] Accessibility description set:', text);\n};\n\n/**\n * Get accessibility description\n */\nconst getAccDescription = (): string => {\n return accDescription;\n};\n\nconst setDiagramTitle = setTitle;\nconst getDiagramTitle = getTitle;\n\n/**\n * Export the database object\n */\nexport const db: RailroadDB = {\n clear,\n setTitle,\n getTitle,\n addRule,\n getRules,\n getRule,\n setAccTitle,\n getAccTitle,\n setAccDescription,\n getAccDescription,\n setDiagramTitle,\n getDiagramTitle,\n};\n\nexport default db;\n", "// cspell:ignore nonterminal\nimport type { DiagramDB } from '../../diagram-api/types.js';\n\n/**\n * AST Node types for Railroad diagram expressions\n */\nexport interface TerminalNode {\n type: 'terminal';\n value: string;\n}\n\nexport interface NonTerminalNode {\n type: 'nonterminal';\n name: string;\n}\n\nexport interface SequenceNode {\n type: 'sequence';\n elements: ASTNode[];\n}\n\nexport interface ChoiceNode {\n type: 'choice';\n alternatives: ASTNode[];\n}\n\nexport interface OptionalNode {\n type: 'optional';\n element: ASTNode;\n}\n\nexport interface RepetitionNode {\n type: 'repetition';\n element: ASTNode;\n min: number; // 0 for *, 1 for +\n max: number; // Infinity for unlimited\n separator?: ASTNode; // Optional separator (e.g., comma)\n}\n\nexport interface SpecialNode {\n type: 'special';\n text: string;\n}\n\n/**\n * Union type for all AST nodes\n */\nexport type ASTNode =\n | TerminalNode\n | NonTerminalNode\n | SequenceNode\n | ChoiceNode\n | OptionalNode\n | RepetitionNode\n | SpecialNode;\n\n/**\n * Railroad diagram rule definition\n */\nexport interface RailroadRule {\n name: string;\n definition: ASTNode;\n comment?: string;\n}\n\n/**\n * Configuration for Railroad diagram styling\n */\nexport interface RailroadStyleOptions {\n // Layout\n compactMode?: boolean;\n\n // Spacing\n padding?: number;\n verticalSeparation?: number;\n horizontalSeparation?: number;\n arcRadius?: number;\n\n // Typography\n fontSize?: number;\n fontFamily?: string;\n\n // Colors - Terminal\n terminalFill?: string;\n terminalStroke?: string;\n terminalTextColor?: string;\n\n // Colors - Non-terminal\n nonTerminalFill?: string;\n nonTerminalStroke?: string;\n nonTerminalTextColor?: string;\n\n // Colors - Lines\n lineColor?: string;\n strokeWidth?: number;\n\n // Colors - Markers\n markerFill?: string;\n\n // Colors - Comment\n commentFill?: string;\n commentStroke?: string;\n commentTextColor?: string;\n\n // Colors - Special\n specialFill?: string;\n specialStroke?: string;\n\n // Other\n ruleNameColor?: string;\n showMarkers?: boolean;\n markerRadius?: number;\n}\n\n/**\n * Railroad diagram configuration (alias for RailroadStyleOptions)\n */\nexport type RailroadDiagramConfig = RailroadStyleOptions;\n\n/**\n * Default configuration\n */\nexport const DEFAULT_RAILROAD_CONFIG: Required<RailroadStyleOptions> = {\n // Layout\n compactMode: false,\n\n // Spacing\n padding: 10,\n verticalSeparation: 8,\n horizontalSeparation: 10,\n arcRadius: 10,\n\n // Typography\n fontSize: 14,\n fontFamily: 'monospace',\n\n // Colors - Terminal\n terminalFill: '#FFFFC0',\n terminalStroke: '#000000',\n terminalTextColor: '#000000',\n\n // Colors - Non-terminal\n nonTerminalFill: '#FFFFFF',\n nonTerminalStroke: '#000000',\n nonTerminalTextColor: '#000000',\n\n // Colors - Lines\n lineColor: '#000000',\n strokeWidth: 2,\n\n // Colors - Markers\n markerFill: '#000000',\n\n // Colors - Comment\n commentFill: '#E8E8E8',\n commentStroke: '#888888',\n commentTextColor: '#666666',\n\n // Colors - Special\n specialFill: '#F0E0FF',\n specialStroke: '#8800CC',\n\n // Other\n ruleNameColor: '#000066',\n showMarkers: true,\n markerRadius: 5,\n};\n\n/**\n * Diagram dimensions for rendering\n */\nexport interface DiagramDimensions {\n width: number;\n height: number;\n up: number; // Height above center line\n down: number; // Height below center line\n}\n\n/**\n * Render result containing SVG element and dimensions\n */\nexport interface RenderResult {\n element: SVGElement;\n dimensions: DiagramDimensions;\n}\n\n/**\n * Railroad diagram Database interface\n */\nexport interface RailroadDB extends DiagramDB {\n clear: () => void;\n setTitle: (title: string) => void;\n getTitle: () => string;\n addRule: (rule: RailroadRule) => void;\n getRules: () => RailroadRule[];\n getRule: (name: string) => RailroadRule | undefined;\n setAccTitle: (title: string) => void;\n getAccTitle: () => string;\n setAccDescription: (description: string) => void;\n getAccDescription: () => string;\n setDiagramTitle: (title: string) => void;\n getDiagramTitle: () => string;\n}\n", "// cspell:ignore nonterminal\nimport type { DiagramStylesProvider } from '../../diagram-api/types.js';\nimport { getConfig as getConfigAPI } from '../../config.js';\nimport { getThemeVariables } from '../../themes/theme-default.js';\nimport { DEFAULT_RAILROAD_CONFIG, type RailroadStyleOptions } from './railroadTypes.js';\n\ntype ThemeVariables = ReturnType<typeof getThemeVariables>;\n\ntype RailroadStyleInput =\n | RailroadStyleOptions\n | ({\n railroad?: RailroadStyleOptions;\n svgId?: string;\n theme?: string;\n look?: string;\n } & Partial<ThemeVariables>);\n\nconst COLOR_VALUE_PATTERN =\n /^#(?:[\\da-f]{3,4}|[\\da-f]{6}|[\\da-f]{8})$|^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\\([\\d\\s%+,./-]+\\)$|^[a-z]+$/i;\nconst FONT_FAMILY_PATTERN = /^[\\w \"',.-]+$/;\nconst RAILROAD_STYLE_OPTION_KEYS = new Set<keyof RailroadStyleOptions>([\n 'compactMode',\n 'padding',\n 'verticalSeparation',\n 'horizontalSeparation',\n 'arcRadius',\n 'fontSize',\n 'fontFamily',\n 'terminalFill',\n 'terminalStroke',\n 'terminalTextColor',\n 'nonTerminalFill',\n 'nonTerminalStroke',\n 'nonTerminalTextColor',\n 'lineColor',\n 'strokeWidth',\n 'markerFill',\n 'commentFill',\n 'commentStroke',\n 'commentTextColor',\n 'specialFill',\n 'specialStroke',\n 'ruleNameColor',\n 'showMarkers',\n 'markerRadius',\n]);\n\nconst isRailroadStyleOptions = (options?: RailroadStyleInput): options is RailroadStyleOptions => {\n if (!options) {\n return false;\n }\n\n return Object.keys(options).every(\n (key) => key === 'railroad' || RAILROAD_STYLE_OPTION_KEYS.has(key as keyof RailroadStyleOptions)\n );\n};\n\nconst extractRailroadOverrides = (options?: RailroadStyleInput): Partial<RailroadStyleOptions> => {\n if (!options) {\n return {};\n }\n\n if ('railroad' in options && options.railroad) {\n return options.railroad;\n }\n\n return isRailroadStyleOptions(options) ? options : {};\n};\n\nconst extractThemeOverrides = (options?: RailroadStyleInput): Partial<ThemeVariables> => {\n if (!options || isRailroadStyleOptions(options)) {\n return {};\n }\n\n const {\n railroad: _railroad,\n svgId: _svgId,\n theme: _theme,\n look: _look,\n ...themeOverrides\n } = options;\n return themeOverrides;\n};\n\nconst sanitizeColorValue = (value: unknown, fallback: string): string => {\n if (typeof value !== 'string') {\n return fallback;\n }\n\n const normalized = value.trim();\n return COLOR_VALUE_PATTERN.test(normalized) ? normalized : fallback;\n};\n\nconst sanitizeFontFamilyValue = (value: unknown, fallback: string): string => {\n if (typeof value !== 'string') {\n return fallback;\n }\n\n const normalized = value.trim();\n return FONT_FAMILY_PATTERN.test(normalized) ? normalized : fallback;\n};\n\nconst sanitizeNumberValue = (value: unknown, fallback: number): number => {\n const parsed =\n typeof value === 'number'\n ? value\n : typeof value === 'string'\n ? Number.parseFloat(value)\n : Number.NaN;\n\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;\n};\n\nconst parseThemeFontSize = (value: unknown): number | undefined => {\n const parsed =\n typeof value === 'number'\n ? value\n : typeof value === 'string'\n ? Number.parseFloat(value)\n : Number.NaN;\n\n return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n};\n\nconst buildThemeDefaults = (themeVariables: ThemeVariables): Required<RailroadStyleOptions> => {\n const fontFamily = sanitizeFontFamilyValue(\n themeVariables.fontFamily,\n DEFAULT_RAILROAD_CONFIG.fontFamily\n );\n const fontSize = parseThemeFontSize(themeVariables.fontSize) ?? DEFAULT_RAILROAD_CONFIG.fontSize;\n\n return {\n ...DEFAULT_RAILROAD_CONFIG,\n fontFamily,\n fontSize,\n terminalFill: sanitizeColorValue(\n themeVariables.secondBkg ?? themeVariables.secondaryColor,\n DEFAULT_RAILROAD_CONFIG.terminalFill\n ),\n terminalStroke: sanitizeColorValue(\n themeVariables.secondaryBorderColor ?? themeVariables.lineColor,\n DEFAULT_RAILROAD_CONFIG.terminalStroke\n ),\n terminalTextColor: sanitizeColorValue(\n themeVariables.secondaryTextColor ?? themeVariables.textColor,\n DEFAULT_RAILROAD_CONFIG.terminalTextColor\n ),\n nonTerminalFill: sanitizeColorValue(\n themeVariables.mainBkg ?? themeVariables.background,\n DEFAULT_RAILROAD_CONFIG.nonTerminalFill\n ),\n nonTerminalStroke: sanitizeColorValue(\n themeVariables.primaryBorderColor ?? themeVariables.lineColor,\n DEFAULT_RAILROAD_CONFIG.nonTerminalStroke\n ),\n nonTerminalTextColor: sanitizeColorValue(\n themeVariables.primaryTextColor ?? themeVariables.textColor,\n DEFAULT_RAILROAD_CONFIG.nonTerminalTextColor\n ),\n lineColor: sanitizeColorValue(themeVariables.lineColor, DEFAULT_RAILROAD_CONFIG.lineColor),\n markerFill: sanitizeColorValue(themeVariables.lineColor, DEFAULT_RAILROAD_CONFIG.markerFill),\n commentFill: sanitizeColorValue(\n themeVariables.labelBackground ?? themeVariables.tertiaryColor,\n DEFAULT_RAILROAD_CONFIG.commentFill\n ),\n commentStroke: sanitizeColorValue(\n themeVariables.tertiaryBorderColor ?? themeVariables.lineColor,\n DEFAULT_RAILROAD_CONFIG.commentStroke\n ),\n commentTextColor: sanitizeColorValue(\n themeVariables.tertiaryTextColor ?? themeVariables.textColor,\n DEFAULT_RAILROAD_CONFIG.commentTextColor\n ),\n specialFill: sanitizeColorValue(\n themeVariables.tertiaryColor ?? themeVariables.secondaryColor,\n DEFAULT_RAILROAD_CONFIG.specialFill\n ),\n specialStroke: sanitizeColorValue(\n themeVariables.tertiaryBorderColor ?? themeVariables.secondaryBorderColor,\n DEFAULT_RAILROAD_CONFIG.specialStroke\n ),\n ruleNameColor: sanitizeColorValue(\n themeVariables.titleColor ?? themeVariables.textColor,\n DEFAULT_RAILROAD_CONFIG.ruleNameColor\n ),\n };\n};\n\nexport const buildRailroadStyleOptions = (\n options?: RailroadStyleInput\n): Required<RailroadStyleOptions> => {\n const currentConfig = getConfigAPI();\n const themeVariables = {\n ...getThemeVariables(),\n ...(currentConfig.themeVariables ?? {}),\n ...extractThemeOverrides(options),\n } as ThemeVariables;\n const themeDefaults = buildThemeDefaults(themeVariables);\n const railroadOptions = {\n ...(currentConfig.railroad ?? {}),\n ...extractRailroadOverrides(options),\n } as RailroadStyleOptions;\n\n return {\n compactMode: railroadOptions.compactMode ?? themeDefaults.compactMode,\n padding: sanitizeNumberValue(railroadOptions.padding, themeDefaults.padding),\n verticalSeparation: sanitizeNumberValue(\n railroadOptions.verticalSeparation,\n themeDefaults.verticalSeparation\n ),\n horizontalSeparation: sanitizeNumberValue(\n railroadOptions.horizontalSeparation,\n themeDefaults.horizontalSeparation\n ),\n arcRadius: sanitizeNumberValue(railroadOptions.arcRadius, themeDefaults.arcRadius),\n fontSize: sanitizeNumberValue(railroadOptions.fontSize, themeDefaults.fontSize),\n fontFamily: sanitizeFontFamilyValue(railroadOptions.fontFamily, themeDefaults.fontFamily),\n terminalFill: sanitizeColorValue(railroadOptions.terminalFill, themeDefaults.terminalFill),\n terminalStroke: sanitizeColorValue(\n railroadOptions.terminalStroke,\n themeDefaults.terminalStroke\n ),\n terminalTextColor: sanitizeColorValue(\n railroadOptions.terminalTextColor,\n themeDefaults.terminalTextColor\n ),\n nonTerminalFill: sanitizeColorValue(\n railroadOptions.nonTerminalFill,\n themeDefaults.nonTerminalFill\n ),\n nonTerminalStroke: sanitizeColorValue(\n railroadOptions.nonTerminalStroke,\n themeDefaults.nonTerminalStroke\n ),\n nonTerminalTextColor: sanitizeColorValue(\n railroadOptions.nonTerminalTextColor,\n themeDefaults.nonTerminalTextColor\n ),\n lineColor: sanitizeColorValue(railroadOptions.lineColor, themeDefaults.lineColor),\n strokeWidth: sanitizeNumberValue(railroadOptions.strokeWidth, themeDefaults.strokeWidth),\n markerFill: sanitizeColorValue(railroadOptions.markerFill, themeDefaults.markerFill),\n commentFill: sanitizeColorValue(railroadOptions.commentFill, themeDefaults.commentFill),\n commentStroke: sanitizeColorValue(railroadOptions.commentStroke, themeDefaults.commentStroke),\n commentTextColor: sanitizeColorValue(\n railroadOptions.commentTextColor,\n themeDefaults.commentTextColor\n ),\n specialFill: sanitizeColorValue(railroadOptions.specialFill, themeDefaults.specialFill),\n specialStroke: sanitizeColorValue(railroadOptions.specialStroke, themeDefaults.specialStroke),\n ruleNameColor: sanitizeColorValue(railroadOptions.ruleNameColor, themeDefaults.ruleNameColor),\n showMarkers: railroadOptions.showMarkers ?? themeDefaults.showMarkers,\n markerRadius: sanitizeNumberValue(railroadOptions.markerRadius, themeDefaults.markerRadius),\n };\n};\n\n/**\n * Generate CSS styles for Railroad diagrams\n */\nexport const getStyles: DiagramStylesProvider = (options?: RailroadStyleInput): string => {\n const {\n fontFamily,\n fontSize,\n terminalFill,\n terminalStroke,\n terminalTextColor,\n nonTerminalFill,\n nonTerminalStroke,\n nonTerminalTextColor,\n lineColor,\n strokeWidth,\n markerFill,\n commentFill,\n commentStroke,\n commentTextColor,\n specialFill,\n specialStroke,\n ruleNameColor,\n } = buildRailroadStyleOptions(options);\n\n return `\n .railroad-diagram {\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n }\n\n .railroad-terminal rect {\n fill: ${terminalFill};\n stroke: ${terminalStroke};\n stroke-width: ${strokeWidth}px;\n }\n\n .railroad-terminal text {\n fill: ${terminalTextColor};\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n text-anchor: middle;\n dominant-baseline: middle;\n }\n\n .railroad-nonterminal rect {\n fill: ${nonTerminalFill};\n stroke: ${nonTerminalStroke};\n stroke-width: ${strokeWidth}px;\n }\n\n .railroad-nonterminal text {\n fill: ${nonTerminalTextColor};\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n text-anchor: middle;\n dominant-baseline: middle;\n }\n\n .railroad-line {\n stroke: ${lineColor};\n stroke-width: ${strokeWidth}px;\n fill: none;\n }\n\n .railroad-start circle,\n .railroad-end circle {\n fill: ${markerFill};\n }\n\n .railroad-comment ellipse {\n fill: ${commentFill};\n stroke: ${commentStroke};\n stroke-width: ${strokeWidth}px;\n }\n\n .railroad-comment text {\n fill: ${commentTextColor};\n font-style: italic;\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n text-anchor: middle;\n dominant-baseline: middle;\n }\n\n .railroad-special rect {\n fill: ${specialFill};\n stroke: ${specialStroke};\n stroke-width: ${strokeWidth}px;\n stroke-dasharray: 5,3;\n }\n\n .railroad-special text {\n fill: ${nonTerminalTextColor};\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n text-anchor: middle;\n dominant-baseline: middle;\n }\n\n .railroad-rule-name {\n font-weight: bold;\n fill: ${ruleNameColor};\n font-family: ${fontFamily};\n font-size: ${fontSize}px;\n }\n\n .railroad-group {\n /* Grouping container, no specific styles */\n }\n`;\n};\n\nexport default getStyles;\n", "// cspell:ignore nonterminal\nimport type d3 from 'd3';\nimport type { DrawDefinition, SVG } from '../../diagram-api/types.js';\nimport type { ASTNode, RailroadRule, RenderResult } from './railroadTypes.js';\nimport { log } from '../../logger.js';\nimport { getConfig as getConfigAPI } from '../../config.js';\nimport { selectSvgElement } from '../../rendering-util/selectSvgElement.js';\nimport { configureSvgSize } from '../../setupGraphViewbox.js';\nimport { db } from './railroadDb.js';\nimport { buildRailroadStyleOptions } from './styles.js';\n\ntype SVGGroup = d3.Selection<SVGGElement, unknown, Element | null, unknown>;\n\n/**\n * SVG Path builder utility\n */\nclass PathBuilder {\n private d = '';\n\n moveTo(x: number, y: number): this {\n this.d += `M ${x} ${y} `;\n return this;\n }\n\n lineTo(x: number, y: number): this {\n this.d += `L ${x} ${y} `;\n return this;\n }\n\n horizontalTo(x: number): this {\n this.d += `H ${x} `;\n return this;\n }\n\n verticalTo(y: number): this {\n this.d += `V ${y} `;\n return this;\n }\n\n arcTo(\n rx: number,\n ry: number,\n rotation: number,\n largeArc: boolean,\n sweep: boolean,\n x: number,\n y: number\n ): this {\n this.d += `A ${rx} ${ry} ${rotation} ${largeArc ? 1 : 0} ${sweep ? 1 : 0} ${x} ${y} `;\n return this;\n }\n\n build(): string {\n return this.d.trim();\n }\n}\n\n/**\n * Railroad diagram renderer\n */\nclass RailroadRenderer {\n private svg: SVG;\n private config: ReturnType<typeof buildRailroadStyleOptions>;\n private textCache = new Map<string, { width: number; height: number }>();\n\n constructor(svg: SVG, config = buildRailroadStyleOptions()) {\n this.svg = svg;\n this.config = config;\n }\n\n /**\n * Measure text dimensions\n */\n private measureText(text: string): { width: number; height: number } {\n if (this.textCache.has(text)) {\n return this.textCache.get(text)!;\n }\n\n // Create temporary text element to measure\n const tempText = this.svg\n .append('text')\n .attr('font-family', this.config.fontFamily)\n .attr('font-size', this.config.fontSize)\n .text(text);\n\n const bbox = tempText.node()!.getBBox();\n const dimensions = { width: bbox.width, height: bbox.height };\n\n tempText.remove();\n this.textCache.set(text, dimensions);\n\n return dimensions;\n }\n\n /**\n * Render terminal symbol (rounded rectangle)\n */\n private renderTerminal(parent: SVG | SVGGroup, value: string): RenderResult {\n const textDim = this.measureText(value);\n const width = textDim.width + this.config.padding * 2;\n const height = textDim.height + this.config.padding * 2;\n\n const group = parent.append('g').attr('class', 'railroad-terminal');\n\n // Rounded rectangle\n group\n .append('rect')\n .attr('x', 0)\n .attr('y', 0)\n .attr('width', width)\n .attr('height', height)\n .attr('rx', 10)\n .attr('ry', 10);\n\n // Text\n group\n .append('text')\n .attr('x', width / 2)\n .attr('y', height / 2)\n .text(value);\n\n return {\n element: group.node()!,\n dimensions: {\n width,\n height,\n up: height / 2,\n down: height / 2,\n },\n };\n }\n\n /**\n * Render non-terminal symbol (rectangle)\n */\n private renderNonTerminal(parent: SVG | SVGGroup, name: string): RenderResult {\n const textDim = this.measureText(name);\n const width = textDim.width + this.config.padding * 2;\n const height = textDim.height + this.config.padding * 2;\n\n const group = parent.append('g').attr('class', 'railroad-nonterminal');\n\n // Rectangle\n group.append('rect').attr('x', 0).attr('y', 0).attr('width', width).attr('height', height);\n\n // Text\n group\n .append('text')\n .attr('x', width / 2)\n .attr('y', height / 2)\n .text(name);\n\n return {\n element: group.node()!,\n dimensions: {\n width,\n height,\n up: height / 2,\n down: height / 2,\n },\n };\n }\n\n /**\n * Render sequence (horizontal concatenation)\n */\n private renderSequence(parent: SVG | SVGGroup, elements: ASTNode[]): RenderResult {\n const rendered = elements.map((e) => this.renderExpression(parent, e));\n\n let totalWidth = 0;\n let maxUp = 0;\n let maxDown = 0;\n\n for (const r of rendered) {\n totalWidth += r.dimensions.width;\n maxUp = Math.max(maxUp, r.dimensions.up);\n maxDown = Math.max(maxDown, r.dimensions.down);\n }\n\n totalWidth += (rendered.length - 1) * this.config.horizontalSeparation;\n\n const group = parent.append('g').attr('class', 'railroad-sequence');\n let x = 0;\n\n for (let i = 0; i < rendered.length; i++) {\n const r = rendered[i];\n const y = maxUp - r.dimensions.up;\n\n // Position element\n const elem = group.node()!.appendChild(r.element);\n elem.setAttribute('transform', `translate(${x}, ${y})`);\n\n // Draw connecting line to next element\n if (i < rendered.length - 1) {\n const lineX1 = x + r.dimensions.width;\n const lineX2 = lineX1 + this.config.horizontalSeparation;\n const lineY = maxUp;\n\n group\n .append('path')\n .attr('class', 'railroad-line')\n .attr('d', new PathBuilder().moveTo(lineX1, lineY).lineTo(lineX2, lineY).build());\n }\n\n x += r.dimensions.width + this.config.horizontalSeparation;\n }\n\n return {\n element: group.node()!,\n dimensions: {\n width: totalWidth,\n height: maxUp + maxDown,\n up: maxUp,\n down: maxDown,\n },\n };\n }\n\n /**\n * Render choice (vertical alternatives)\n */\n private renderChoice(parent: SVG | SVGGroup, alternatives: ASTNode[]): RenderResult {\n const rendered = alternatives.map((a) => this.renderExpression(parent, a));\n\n let maxWidth = 0;\n let totalHeight = 0;\n\n for (const r of rendered) {\n maxWidth = Math.max(maxWidth, r.dimensions.width);\n totalHeight += r.dimensions.height;\n }\n\n totalHeight += (rendered.length - 1) * this.config.verticalSeparation;\n\n const arcRadius = this.config.arcRadius;\n const arcWidth = arcRadius * 4;\n const totalWidth = maxWidth + arcWidth;\n\n const group = parent.append('g').attr('class', 'railroad-choice');\n let y = 0;\n const centerY = totalHeight / 2;\n\n for (const r of rendered) {\n const elemY = y;\n const elemCenterY = elemY + r.dimensions.up;\n\n // Position element in the center\n const elemX = arcRadius * 2 + (maxWidth - r.dimensions.width) / 2;\n const elem = group.node()!.appendChild(r.element);\n elem.setAttribute('transform', `translate(${elemX}, ${elemY})`);\n\n // Left arc from center to this alternative\n const leftPath = new PathBuilder();\n const isBelowCenter = elemCenterY > centerY;\n if (elemCenterY === centerY) {\n leftPath.moveTo(0, centerY).lineTo(elemX, elemCenterY);\n } else {\n leftPath\n .moveTo(0, centerY)\n .arcTo(\n arcRadius,\n arcRadius,\n 0,\n false,\n isBelowCenter,\n arcRadius,\n centerY + (isBelowCenter ? arcRadius : -arcRadius)\n )\n .lineTo(arcRadius, elemCenterY - (isBelowCenter ? arcRadius : -arcRadius))\n .arcTo(arcRadius, arcRadius, 0, false, !isBelowCenter, arcRadius * 2, elemCenterY)\n .lineTo(elemX, elemCenterY);\n }\n\n group.append('path').attr('class', 'railroad-line').attr('d', leftPath.build());\n\n // Right arc from this alternative to center\n const rightPath = new PathBuilder();\n const rightStart = elemX + r.dimensions.width;\n const rightLaneX = totalWidth - arcRadius * 2;\n if (elemCenterY === centerY) {\n rightPath.moveTo(rightStart, elemCenterY).lineTo(totalWidth, centerY);\n } else {\n rightPath\n .moveTo(rightStart, elemCenterY)\n .lineTo(rightLaneX, elemCenterY)\n .arcTo(\n arcRadius,\n arcRadius,\n 0,\n false,\n !isBelowCenter,\n totalWidth - arcRadius,\n elemCenterY + (isBelowCenter ? -arcRadius : arcRadius)\n )\n .lineTo(totalWidth - arcRadius, centerY + (isBelowCenter ? arcRadius : -arcRadius))\n .arcTo(arcRadius, arcRadius, 0, false, isBelowCenter, totalWidth, centerY);\n }\n\n group.append('path').attr('class', 'railroad-line').attr('d', rightPath.build());\n\n y += r.dimensions.height + this.config.verticalSeparation;\n }\n\n return {\n element: group.node()!,\n dimensions: {\n width: totalWidth,\n height: totalHeight,\n up: centerY,\n down: totalHeight - centerY,\n },\n };\n }\n\n /**\n * Render optional (bypass path above)\n */\n private renderOptional(parent: SVG | SVGGroup, element: ASTNode): RenderResult {\n const inner = this.renderExpression(parent, element);\n const arcRadius = this.config.arcRadius;\n const arcHeight = arcRadius * 2;\n const totalWidth = inner.dimensions.width + arcRadius * 4;\n const totalHeight = inner.dimensions.height + arcHeight;\n\n const group = parent.append('g').attr('class', 'railroad-optional');\n\n // Position main element\n const elemX = arcRadius * 2;\n const elemY = arcHeight;\n const elem = group.node()!.appendChild(inner.element);\n elem.setAttribute('transform', `translate(${elemX}, ${elemY})`);\n\n const centerY = elemY + inner.dimensions.up;\n\n // Lower path (through element)\n const lowerPath = new PathBuilder().moveTo(0, centerY).lineTo(arcRadius * 2, centerY);\n group.append('path').attr('class', 'railroad-line').attr('d', lowerPath.build());\n\n const lowerPath2 = new PathBuilder()\n .moveTo(elemX + inner.dimensions.width, centerY)\n .lineTo(totalWidth, centerY);\n group.append('path').attr('class', 'railroad-line').attr('d', lowerPath2.build());\n\n // Upper bypass path\n const bypassPath = new PathBuilder()\n .moveTo(0, centerY)\n .arcTo(arcRadius, arcRadius, 0, false, false, arcRadius, centerY - arcRadius)\n .lineTo(arcRadius, arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, true, arcRadius * 2, 0)\n .lineTo(totalWidth - arcRadius * 2, 0)\n .arcTo(arcRadius, arcRadius, 0, false, true, totalWidth - arcRadius, arcRadius)\n .lineTo(totalWidth - arcRadius, centerY - arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, false, totalWidth, centerY);\n\n group.append('path').attr('class', 'railroad-line').attr('d', bypassPath.build());\n\n return {\n element: group.node()!,\n dimensions: {\n width: totalWidth,\n height: totalHeight,\n up: centerY,\n down: totalHeight - centerY,\n },\n };\n }\n\n /**\n * Render repetition (loop back path)\n */\n private renderRepetition(parent: SVG | SVGGroup, element: ASTNode, min: number): RenderResult {\n const inner = this.renderExpression(parent, element);\n const arcRadius = this.config.arcRadius;\n const arcHeight = arcRadius * 2;\n const totalWidth = inner.dimensions.width + arcRadius * 4;\n\n // For *, add bypass on top; for +, no bypass\n const hasBypass = min === 0;\n const totalHeight = inner.dimensions.height + arcHeight + (hasBypass ? arcHeight : 0);\n\n const group = parent.append('g').attr('class', 'railroad-repetition');\n\n // Position main element\n const elemX = arcRadius * 2;\n const elemY = hasBypass ? arcHeight : 0;\n const elem = group.node()!.appendChild(inner.element);\n elem.setAttribute('transform', `translate(${elemX}, ${elemY})`);\n\n const centerY = elemY + inner.dimensions.up;\n\n // Forward path\n group\n .append('path')\n .attr('class', 'railroad-line')\n .attr(\n 'd',\n new PathBuilder()\n .moveTo(0, centerY)\n .lineTo(arcRadius * 2, centerY)\n .build()\n );\n\n group\n .append('path')\n .attr('class', 'railroad-line')\n .attr(\n 'd',\n new PathBuilder()\n .moveTo(elemX + inner.dimensions.width, centerY)\n .lineTo(totalWidth, centerY)\n .build()\n );\n\n // Loop back path (below)\n const loopY = elemY + inner.dimensions.height + arcRadius;\n const loopPath = new PathBuilder()\n .moveTo(elemX + inner.dimensions.width, centerY)\n .arcTo(\n arcRadius,\n arcRadius,\n 0,\n false,\n true,\n elemX + inner.dimensions.width + arcRadius,\n centerY + arcRadius\n )\n .lineTo(elemX + inner.dimensions.width + arcRadius, loopY)\n .arcTo(\n arcRadius,\n arcRadius,\n 0,\n false,\n true,\n elemX + inner.dimensions.width,\n loopY + arcRadius\n )\n .lineTo(arcRadius * 2, loopY + arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, true, arcRadius, loopY)\n .lineTo(arcRadius, centerY + arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, true, arcRadius * 2, centerY);\n\n group.append('path').attr('class', 'railroad-line').attr('d', loopPath.build());\n\n // Optional bypass path (for *)\n if (hasBypass) {\n const bypassPath = new PathBuilder()\n .moveTo(0, centerY)\n .arcTo(arcRadius, arcRadius, 0, false, false, arcRadius, centerY - arcRadius)\n .lineTo(arcRadius, arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, true, arcRadius * 2, 0)\n .lineTo(totalWidth - arcRadius * 2, 0)\n .arcTo(arcRadius, arcRadius, 0, false, true, totalWidth - arcRadius, arcRadius)\n .lineTo(totalWidth - arcRadius, centerY - arcRadius)\n .arcTo(arcRadius, arcRadius, 0, false, false, totalWidth, centerY);\n\n group.append('path').attr('class', 'railroad-line').attr('d', bypassPath.build());\n }\n\n return {\n element: group.node()!,\n dimensions: {\n width: totalWidth,\n height: totalHeight,\n up: centerY,\n down: totalHeight - centerY,\n },\n };\n }\n\n /**\n * Render special sequence\n */\n private renderSpecial(parent: SVG | SVGGroup, text: string): RenderResult {\n const textDim = this.measureText('? ' + text + ' ?');\n const width = textDim.width + this.config.padding * 2;\n const height = textDim.height + this.config.padding * 2;\n\n const group = parent.append('g').attr('class', 'railroad-special');\n\n // Rectangle with dashed border\n group.append('rect').attr('x', 0).attr('y', 0).attr('width', width).attr('height', height);\n\n // Text\n group\n .append('text')\n .attr('x', width / 2)\n .attr('y', height / 2)\n .text('? ' + text + ' ?');\n\n return {\n element: group.node()!,\n dimensions: {\n width,\n height,\n up: height / 2,\n down: height / 2,\n },\n };\n }\n\n /**\n * Render an expression (recursive)\n */\n renderExpression(parent: SVG | SVGGroup, node: ASTNode): RenderResult {\n switch (node.type) {\n case 'terminal':\n return this.renderTerminal(parent, node.value);\n\n case 'nonterminal':\n return this.renderNonTerminal(parent, node.name);\n\n case 'sequence':\n return this.renderSequence(parent, node.elements);\n\n case 'choice':\n return this.renderChoice(parent, node.alternatives);\n\n case 'optional':\n return this.renderOptional(parent, node.element);\n\n case 'repetition':\n return this.renderRepetition(parent, node.element, node.min);\n\n case 'special':\n return this.renderSpecial(parent, node.text);\n\n default:\n throw new Error(`Unknown node type: ${(node as any).type}`);\n }\n }\n\n /**\n * Render a single rule\n */\n renderRule(rule: RailroadRule, y: number): { height: number; width: number } {\n const group = this.svg\n .append('g')\n .attr('class', 'railroad-rule')\n .attr('transform', `translate(0, ${y})`);\n\n const ruleName = rule.name + ' =';\n const nameWidth = this.measureText(ruleName).width + 20;\n const definitionX = nameWidth + 20;\n\n // Render definition\n const defGroup: SVGGroup = group.append('g');\n const result = this.renderExpression(defGroup, rule.definition);\n const baselineY = Math.max(20, result.dimensions.up);\n const definitionY = baselineY - result.dimensions.up;\n defGroup.attr('transform', `translate(${definitionX}, ${definitionY})`);\n\n const nameGroup = group.append('g').attr('class', 'railroad-rule-name-group');\n nameGroup\n .append('text')\n .attr('class', 'railroad-rule-name')\n .attr('x', 0)\n .attr('y', baselineY)\n .text(ruleName);\n\n // Start marker\n const startMarker = group.append('g').attr('class', 'railroad-start');\n startMarker\n .append('circle')\n .attr('cx', nameWidth)\n .attr('cy', baselineY)\n .attr('r', this.config.markerRadius);\n\n // End marker\n const endMarker = group.append('g').attr('class', 'railroad-end');\n endMarker\n .append('circle')\n .attr('cx', definitionX + result.dimensions.width + 10)\n .attr('cy', baselineY)\n .attr('r', this.config.markerRadius);\n\n // Line from start to definition\n group\n .append('path')\n .attr('class', 'railroad-line')\n .attr(\n 'd',\n new PathBuilder()\n .moveTo(nameWidth + this.config.markerRadius, baselineY)\n .lineTo(definitionX, baselineY)\n .build()\n );\n\n // Line from definition to end\n group\n .append('path')\n .attr('class', 'railroad-line')\n .attr(\n 'd',\n new PathBuilder()\n .moveTo(definitionX + result.dimensions.width, baselineY)\n .lineTo(definitionX + result.dimensions.width + 10 - this.config.markerRadius, baselineY)\n .build()\n );\n\n return {\n height: Math.max(40, definitionY + result.dimensions.height + this.config.padding * 2),\n width: definitionX + result.dimensions.width + 10 + this.config.markerRadius,\n };\n }\n\n /**\n * Render all rules\n */\n renderDiagram(rules: RailroadRule[]): { width: number; height: number } {\n let y = this.config.padding;\n let maxWidth = 0;\n\n for (const rule of rules) {\n const result = this.renderRule(rule, y);\n y += result.height + this.config.verticalSeparation;\n maxWidth = Math.max(maxWidth, result.width);\n }\n\n return {\n width: maxWidth + this.config.padding * 2,\n height: y + this.config.padding,\n };\n }\n}\n\nconst configureRailroadSvgSize = (\n svg: SVG,\n dimensions: { width: number; height: number },\n useMaxWidth: boolean\n): void => {\n configureSvgSize(svg, dimensions.height, dimensions.width, useMaxWidth);\n svg.attr('viewBox', `0 0 ${dimensions.width} ${dimensions.height}`);\n};\n\n/**\n * Main draw function\n */\nconst draw: DrawDefinition = (text, id, _version) => {\n log.debug('[Railroad] Rendering diagram\\n' + text);\n\n try {\n const svg = selectSvgElement(id);\n svg.attr('class', 'railroad-diagram');\n const railroadConfig = getConfigAPI().railroad;\n const useMaxWidth = railroadConfig?.useMaxWidth ?? true;\n\n const rules = db.getRules();\n log.debug(`[Railroad] Rendering ${rules.length} rules`);\n\n if (rules.length === 0) {\n log.warn('[Railroad] No rules to render');\n configureRailroadSvgSize(svg, { height: 100, width: 200 }, useMaxWidth);\n return;\n }\n\n const renderer = new RailroadRenderer(svg, buildRailroadStyleOptions());\n const dimensions = renderer.renderDiagram(rules);\n\n configureRailroadSvgSize(svg, dimensions, useMaxWidth);\n\n log.debug('[Railroad] Render complete');\n } catch (error) {\n log.error('[Railroad] Render error:', error);\n throw error;\n }\n};\n\nexport const renderer = { draw };\nexport default renderer;\n"],
"mappings": "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