import { D as DgmoError, P as PaletteConfig, T as TagGroup, a as PaletteColors, C as CompactViewState, g as TagEntry } from './tag-groups-DrHT2tEc.js'; export { h as DecodedDiagramUrl, c as DgmoSeverity, i as EncodeDiagramUrlOptions, j as EncodeDiagramUrlResult, k as autoTagColorCycle, l as decodeDiagramUrl, m as decodeViewState, n as encodeDiagramUrl, o as encodeViewState, f as formatDgmoError, p as makeDgmoError, t as tagAttrKey } from './tag-groups-DrHT2tEc.js'; import { M as MapDataSource, P as ParsedMap, b as MapData, d as ResolvedMap, e as MapLayoutLegend, f as GeoExtent } from './d3--y67plmW.js'; export { A as AirportData, B as BoundaryTopology, G as Gazetteer, a as GazetteerEntry, g as MapDirectives, h as MapEdge, i as MapPoi, j as MapRegion, k as MapRoute, l as PoiPos, m as ProjectionFamily, R as RegionName, c as RegionNames, n as ResolvedEdge, o as ResolvedPoi, p as ResolvedRegion, q as ResolvedRoute, r as renderForExport } from './d3--y67plmW.js'; export { b as CHART_TYPE_DESCRIPTIONS, C as ChartTypeId, a as ChartTypeMeta, R as RenderCategory, d as chartTypeParsers, c as chartTypes, e as getAllChartTypes, f as getAvailablePalettes, g as getPalette, h as getRenderCategory, i as isExtendedChartType, j as isValidHex, k as knownChartTypeIds, p as parseDgmo, l as parseDgmoChartType, m as registerPalette, p as validate } from './dgmo-router-CY5j16Pl.js'; import { Selection } from 'd3-selection'; import * as d3Scale from 'd3-scale'; import { P as ParsedOrg, F as FillMode, R as RaciMarker, a as ParsedRaci, b as RaciVariant, c as RaciTask } from './chart-meta-lP8Rl19E.js'; export { A as ALL_CHART_TYPES, I as ImportSource, O as OrgNode, d as RaciPhase, e as RaciRoleAssignment, f as ReadFileFn, g as ResolveImportsResult, h as contrastText, i as findOrgNodeIdByName, j as getSeriesColors, k as hexToHSL, l as hexToHSLString, m as hslToHex, n as mix, o as normalizePertSourceForShare, p as parseFirstLine, q as parseOrg, r as parseRaci, s as resolveOrgImports, t as shade, u as shapeFill, v as tint } from './chart-meta-lP8Rl19E.js'; import { GeoProjection } from 'd3-geo'; export { M as MapCompletionOptions, a as MapLocationMatch, b as MapPlaceCompletion, c as MapRegionCompletion, T as Theme, d as completeMapPlaces, e as completeMapRegions, p as palettes, s as searchMapLocations, t as themes } from './themes-GWhsabnx.js'; /** * Stable diagnostic codes for in-arrow label parsing errors. * * **Active codes** — emitted by the parser pipeline today: * - `ARROW_SUBSTRING_IN_LABEL` (TD-13) * - `CONTROL_CHAR_IN_LABEL` (TD-14) * * See `docs/dgmo-language-spec-decisions.md` → TD-16 for the rationale. */ declare const ARROW_DIAGNOSTIC_CODES: { /** Active: label contains `->` or `~>` substring (TD-13). */ readonly ARROW_SUBSTRING_IN_LABEL: "E_ARROW_SUBSTRING_IN_LABEL"; /** Active: label contains a forbidden control character (TD-14). */ readonly CONTROL_CHAR_IN_LABEL: "E_CONTROL_CHAR_IN_LABEL"; }; /** * Validate an in-arrow label against the TD-13 and TD-14 character-set * contract. Returns diagnostics (possibly empty). Does NOT mutate the label — * callers that want a normalized label should trim before calling. * * TD-13: label must not contain the substrings "->" or "~>". * TD-14: label must not contain C0 control chars other than tab, and no DEL. */ declare function validateLabelCharacters(label: string, lineNumber: number): DgmoError[]; interface ParseInArrowLabelResult { /** Cleaned label (trimmed; `undefined` if empty after trim per TD-10). */ label: string | undefined; diagnostics: DgmoError[]; } /** * Normalize and validate a raw in-arrow label. * * Behavior: * - Trims leading/trailing whitespace (TD-8: internal whitespace preserved). * - Empty-after-trim → `{ label: undefined }` (TD-10 normalization). * - TD-13: emits `E_ARROW_SUBSTRING_IN_LABEL` if `->` or `~>` is present. * - TD-14: emits `E_CONTROL_CHAR_IN_LABEL` for forbidden control chars. * * This helper is intentionally chart-agnostic: it operates on an already * extracted label string, leaving each chart's existing arrow-finding * tokenization in place. Edges no longer have a color slot on any chart * type (see spec §1.7 "Edge color is not a feature"); arrow content is * pure label text. */ declare function parseInArrowLabel(rawLabel: string, lineNumber: number): ParseInArrowLabelResult; /** * Tag a primitive type `T` with a phantom brand `B`. The brand * exists only in the type system — `Brand` is a `string` * at runtime, but TypeScript treats it as nominally distinct from * plain `string` and from any other `Brand`. */ type Brand = T & { readonly __brand: B; }; declare const atlasPalette: PaletteConfig; declare const blueprintPalette: PaletteConfig; declare const catppuccinPalette: PaletteConfig; declare const nordPalette: PaletteConfig; declare const slatePalette: PaletteConfig; declare const tidewaterPalette: PaletteConfig; declare const tokyoNightPalette: PaletteConfig; type TimelineSort = 'time' | 'group' | 'tag'; interface TimelineEvent { date: string; endDate: string | null; label: string; group: string | null; metadata: Record; lineNumber: number; uncertain?: boolean; } interface TimelineGroup { name: string; color: string | null; metadata: Record; lineNumber: number; } interface TimelineEra { startDate: string; endDate: string; label: string; color: string | null; lineNumber: number; } interface TimelineMarker { date: string; label: string; color: string | null; lineNumber: number; } interface D3ExportDimensions { width?: number; height?: number; /** Map-only: when true, the map renderer suppresses its global stretch-fill and * contain-fits (letterbox) instead. Set by `mapExportDimensions` when the export * canvas was clamped/floored away from the map's content aspect, so the * off-aspect canvas doesn't re-distort. Ignored by all non-map renderers. */ preferContain?: boolean; } type VisualizationType = 'slope' | 'wordcloud' | 'arc' | 'timeline' | 'venn' | 'quadrant' | 'sequence' | 'tech-radar' | 'cycle' | 'pyramid' | 'ring'; interface D3DataItem { label: string; values: number[]; color: string | null; lineNumber: number; } interface WordCloudWord { text: string; weight: number; lineNumber: number; } type WordCloudRotate = 'none' | 'mixed' | 'angled'; interface WordCloudOptions { rotate: WordCloudRotate; max: number; minSize: number; maxSize: number; } interface ArcLink { source: string; target: string; value: number; color: string | null; lineNumber: number; } type ArcOrder = 'appearance' | 'name' | 'group' | 'degree'; interface ArcNodeGroup { name: string; nodes: string[]; color: string | null; lineNumber: number; } interface VennSet { name: string; alias: string | null; color: string | null; lineNumber: number; } interface VennOverlap { sets: string[]; label: string | null; lineNumber: number; } interface QuadrantLabel { text: string; color: string | null; lineNumber: number; } interface QuadrantPoint { label: string; x: number; y: number; lineNumber: number; } interface QuadrantLabels { topRight: QuadrantLabel | null; topLeft: QuadrantLabel | null; bottomLeft: QuadrantLabel | null; bottomRight: QuadrantLabel | null; } /** Fields every visualization shares. */ interface ParsedVizBase { title: string | null; titleLineNumber: number | null; /** When true, the renderer suppresses the chart title. */ noTitle?: boolean; /** * §1.9 fill family — `'solid'` renders filled marks at full intent * saturation, `'outline'` drops the fill to the theme background (color on * the stroke). Honored by renderers with a fillable surface (e.g. venn set * circles); a no-op for line/point types. Absent ⇒ canonical muted tint. */ fillMode?: 'solid' | 'outline'; diagnostics: DgmoError[]; error: string | null; } interface ParsedSlope extends ParsedVizBase { type: 'slope'; periods: string[]; data: D3DataItem[]; noName?: boolean; noValue?: boolean; noPercent?: boolean; } interface ParsedArc extends ParsedVizBase { type: 'arc'; orientation: 'horizontal' | 'vertical'; links: ArcLink[]; arcOrder: ArcOrder; arcNodeGroups: ArcNodeGroup[]; noName?: boolean; noValue?: boolean; noPercent?: boolean; /** `layout arc|chord` override (#26). `chord` re-renders the same edges as a * circular chord; absent ⇒ the `arc` linear preset. */ layout?: 'arc' | 'chord'; } interface ParsedTimeline extends ParsedVizBase { type: 'timeline'; orientation: 'horizontal' | 'vertical'; timelineEvents: TimelineEvent[]; timelineGroups: TimelineGroup[]; timelineEras: TimelineEra[]; timelineMarkers: TimelineMarker[]; timelineTagGroups: TagGroup[]; timelineSort: TimelineSort | null; timelineDefaultSwimlaneTG?: string; timelineScale: boolean; timelineSwimlanes: boolean; /** Authored `active-tag ` directive (§15.6); resolved at render. */ timelineActiveTag?: string; /** §1.9 fill family (`'solid'` | `'outline'`); absent ⇒ 25% tint. */ fillMode?: 'solid' | 'outline'; /** When true, the renderer suppresses the tag legend and the vertical band * it would occupy (#48). */ noLegend?: boolean; } interface ParsedWordcloud extends ParsedVizBase { type: 'wordcloud'; words: WordCloudWord[]; cloudOptions: WordCloudOptions; } interface ParsedVenn extends ParsedVizBase { type: 'venn'; vennSets: VennSet[]; vennOverlaps: VennOverlap[]; noName?: boolean; noValue?: boolean; noPercent?: boolean; } interface ParsedQuadrant extends ParsedVizBase { type: 'quadrant'; quadrantLabels: QuadrantLabels; quadrantPoints: QuadrantPoint[]; quadrantXAxis: [string, string] | null; quadrantXAxisLineNumber: number | null; quadrantYAxis: [string, string] | null; quadrantYAxisLineNumber: number | null; quadrantTitleLineNumber: number | null; } /** * `sequence` (rendered by its own parser) or an unsupported/empty parse result * (`type: null`). Carries only the base fields — callers branch on `error`. */ interface ParsedVizEmpty extends ParsedVizBase { type: 'sequence' | null; } /** What `parseVisualization` returns: discriminated on `type`. */ type ParsedVisualization = ParsedSlope | ParsedArc | ParsedTimeline | ParsedWordcloud | ParsedVenn | ParsedQuadrant | ParsedVizEmpty; /** * Parses D3 chart text format into structured data. Returns the discriminated * {@link ParsedVisualization} union; internally the single state machine fills a * fat {@link ParsedVizFull} accumulator, which is a structural superset of every * variant, so the narrowing is sound and runtime-identical. */ declare function parseVisualization(content: string, palette?: PaletteColors): ParsedVisualization; type TimelineDurationUnit = 'd' | 'w' | 'm' | 'y' | 'h' | 'min' | 's'; declare function addDurationToDate(startDate: string, amount: number, unit: TimelineDurationUnit): string; declare function parseTimelineDate(s: string): number; /** * Renders a slope chart into the given container using D3. */ declare function renderSlopeChart(container: HTMLDivElement, parsed: ParsedSlope, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions): void; declare function orderArcNodes(links: ArcLink[], order: ArcOrder, groups: ArcNodeGroup[]): string[]; /** * Renders an arc diagram into the given container using D3. */ declare function renderArcDiagram(container: HTMLDivElement, parsed: ParsedArc, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions): void; /** * Converts a DSL date string to a human-readable label. * '1718' → '1718' * '1718-05' → 'May 1718' * '1718-05-22' → 'May 22, 1718' * '2024-06-15 14:30' → 'Jun 15, 2024 14:30' * '2024-06-15 14:30:45' → 'Jun 15, 2024 14:30:45' * '-753' → '753 BCE' (BCE years stored signed) * '-0044-03' → 'Mar 44 BCE' */ declare function formatDateLabel(dateStr: string): string; declare function renderTimeline(container: HTMLDivElement, parsed: ParsedTimeline, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions, activeTagGroup?: string | null, swimlaneTagGroup?: string | null, onTagStateChange?: (activeTagGroup: string | null, swimlaneTagGroup: string | null) => void, viewMode?: boolean, exportMode?: boolean): void; /** * Renders a word cloud into the given container using d3-cloud. */ declare function renderWordCloud(container: HTMLDivElement, parsed: ParsedWordcloud, palette: PaletteColors, _isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions): void; declare function renderVenn(container: HTMLDivElement, parsed: ParsedVenn, palette: PaletteColors, _isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions): void; /** * Renders a quadrant chart using D3. * Displays 4 colored quadrant regions, axis labels, quadrant labels, and data points. */ declare function renderQuadrant(container: HTMLDivElement, parsed: ParsedQuadrant, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: D3ExportDimensions): void; /** * Render DGMO source to an SVG string. * * Automatically detects the chart type, selects the appropriate renderer, * and returns a complete SVG document string. * * @param content - DGMO source text * @param options - Optional theme and palette settings * @returns Object with `svg` (SVG string, empty on error) and `diagnostics` (parse errors/warnings) * * @example * ```ts * import { render } from '@diagrammo/dgmo'; * * const { svg, diagnostics } = await render(`pie Languages * TypeScript: 45 * Python: 30 * Rust: 25`); * ``` */ declare function render(content: string, options?: { theme?: 'light' | 'dark' | 'transparent'; palette?: string; c4Level?: 'context' | 'containers' | 'components' | 'deployment'; c4System?: string; c4Container?: string; tagGroup?: string; /** Legend state for export — controls which tag group is shown in exported SVG. */ legendState?: { activeGroup?: string; hiddenAttributes?: string[]; }; /** View state for export — controls interactive state (collapse, swimlanes, etc.) */ viewState?: CompactViewState; /** * Basemap assets for `map` charts — the data itself, or a loader returning * it. `render()` reads nothing from the filesystem or the network on its * own, so this is the only way a map obtains a basemap, and its presence * here is what tells a caller whether a render can touch the environment. * * - Node / CLI / SSR: pass the `loadMapData` loader from * `@diagrammo/dgmo/advanced`. It is called only when the content really * is a map, so a non-map render never pays for it. * - Browser / Worker / Obsidian: pass your bundled `MapData`. * * Omit it and a map renders empty with an `E_MAP_DATA_NOT_SUPPLIED` * diagnostic. Every other chart type ignores this option. */ mapData?: MapDataSource; /** Bake pure-CSS hover into the exported SVG (no JS). Default ON — embeds * (Obsidian, doc-site wrappers) get hover feedback for free. The desktop * app renders its live preview through direct renderer calls (not this * entry), so it keeps its JS emphasis; pass `false` to opt out. */ bakeHover?: boolean; /** * Canvas to draw onto, in px. Defaults to the 1200x800 export sheet. * * Fitting that sheet to a narrow column inherits its ASPECT, which is how a * one-line goal meter ends up taller than the card holding it. A caller * that knows the shape it wants passes it here. */ width?: number; height?: number; }): Promise<{ svg: string; diagnostics: DgmoError[]; /** Detected chart type (e.g. `map`, `clock`), or undefined when inference * failed. Embed callers use it to pick the default embed background. */ chartType: string | undefined; }>; type ChartType$1 = 'bar' | 'line' | 'pie' | 'polar-area' | 'radar'; interface ChartDataPoint { label: string; value: number; extraValues?: number[]; color?: string; lineNumber: number; } interface ChartEra { start: string; end: string; label: string; color: string | null; lineNumber: number; } interface ParsedChart { type: ChartType$1; title?: string; titleLineNumber?: number; series?: string; seriesLineNumber?: number; xlabel?: string; xlabelLineNumber?: number; ylabel?: string; ylabelLineNumber?: number; /** Right (secondary) y-axis label — set by a `y-right-label` option or a * grouped-series axis header (§15.1 dual-axis line charts). */ yrlabel?: string; yrlabelLineNumber?: number; seriesNames?: string[]; seriesNameLineNumbers?: number[]; seriesNameColors?: (string | undefined)[]; /** Per-series axis assignment, parallel to seriesNames. Present only when the * series block uses the grouped (dual-axis) form; absent ⇒ all left. */ seriesAxes?: ('left' | 'right')[]; /** Bar multi-series layout, set by a `stack` or `group` block header * (consolidation #24). Absent ⇒ single-series bar. Drives stacked vs * clustered rendering in `charts-d3/bar.ts`. */ barLayout?: 'stack' | 'group'; /** Pie hole inner-radius ratio (0–0.9), set by a `hole` directive * (bare ⇒ default). Absent ⇒ solid pie. (#23) */ hole?: number; /** Suppress the pie center total (bare `no-center-total`). The total * shows by default whenever a hole is present. (#23) */ noCenterTotal?: boolean; /** Render a line chart filled, i.e. as an area (bare `fill`). (#25) */ fill?: boolean; orientation?: 'horizontal' | 'vertical'; color?: string; label?: string; noName?: boolean; noValue?: boolean; noPercent?: boolean; /** §1.9 fill family: `'solid'` = full intent saturation, `'outline'` = * theme-background fill with color on the stroke. Absent ⇒ 25% tint. */ fillMode?: 'solid' | 'outline'; /** Cross-chart-type: when true, the renderer suppresses the chart title. */ noTitle?: boolean; /** Cross-chart-type: when true, the renderer suppresses the legend and the * vertical band it would occupy (#48). */ noLegend?: boolean; /** §1.9 `legend-inline`: render the title and the series legend on one line * (title left, legend right) instead of stacking the legend below a centered * title — reclaims a header row. Honoured by the top-center-legend data * charts (bar/line/radar/scatter/function); a no-op elsewhere. Auto-falls * back to the stacked header when the legend can't fit beside the title on a * single row (decision #50). */ legendInline?: boolean; /** Line only: opt out of the data-driven y-axis auto-fit and anchor the * baseline at 0 (magnitude honesty / old ECharts-parity behavior). By * default a line chart fits a padded data-min→max window (§15.1). */ noAutoY?: boolean; data: ChartDataPoint[]; eras?: ChartEra[]; diagnostics: DgmoError[]; error: string | null; } /** * Parses the simple chart text format into a structured object. * * Format (colon-free): * ``` * bar My Chart * series Revenue * * Jan 120 * Feb 200 * Mar 150 * ``` */ declare function parseChart(content: string, palette?: PaletteColors): ParsedChart; /** * Parse a data row line: everything before the last numeric token(s) is the label, * numeric tokens at the end are the values. Values are space-separated. * * Examples: * "Jan 120" → { label: "Jan", values: [120] } * "North America 250" → { label: "North America", values: [250] } * "Q1 10 20 30" → { label: "Q1", values: [10, 20, 30] } * "Revenue 1_000" → { label: "Revenue", values: [1000] } * '"Wi-Fi 6" 70 80' → { label: "Wi-Fi 6", values: [70, 80], quotedLabel: true } * * A fully-quoted leading label is taken verbatim (quotes stripped) and is never * eligible for value peeling — the escape hatch for labels that end in a digit * (`"Wi-Fi 6"`, `"Layer 3"`), mirroring the treemap leaf rule. * * `trailingNumericCount` reports how many consecutive numeric tokens the row * actually ends with, which may exceed `values.length` when `expectedValues` * caps the walk. Callers use it to flag an over-long row instead of silently * absorbing the surplus numbers into the label. * * Returns null if the line has no numeric value at the end. */ declare function parseDataRowValues(line: string, options?: { multiValue?: boolean; expectedValues?: number; }): { label: string; values: number[]; /** Label prefix with every trailing numeric token removed (diagnostics use * this so the message names "Armor", not the corrupted "Armor 50 60"). */ bareLabel: string; trailingNumericCount: number; quotedLabel: boolean; } | null; interface LegendState { activeGroup: string | null; hiddenAttributes?: Set; controlsExpanded?: boolean; } interface LegendCallbacks { onGroupToggle?: (groupName: string) => void; onVisibilityToggle?: (attribute: string) => void; onStateChange?: (newState: LegendState) => void; /** Called when an entry is hovered. Chart renderers can use this for cross-element highlighting. */ onEntryHover?: (groupName: string, entryValue: string | null) => void; /** Called after each group is rendered — lets chart renderers inject custom elements (swimlane icons, etc.) */ onGroupRendered?: (groupName: string, groupEl: D3Sel, isActive: boolean) => void; /** Called when the controls group gear pill is clicked (expand/collapse) */ onControlsExpand?: () => void; /** Called when a controls group toggle entry is clicked */ onControlsToggle?: (toggleId: string, active: boolean) => void; } interface LegendPosition { placement: 'top-center'; titleRelation: 'below-title' | 'inline-with-title'; } type LegendMode = 'preview' | 'export'; type LegendControlExportBehavior = 'include' | 'strip' | 'static'; interface LegendControl { id: string; /** SVG markup for the control icon, or a string label */ icon: string; label?: string; exportBehavior: LegendControlExportBehavior; onClick?: () => void; children?: LegendControlEntry[]; } interface LegendControlEntry { id: string; label: string; isActive?: boolean; onClick?: () => void; } interface ControlsGroupToggle { id: string; /** Only 'toggle' is implemented in v1. 'select' and 'action' future-proof for Infra playback etc. */ type: 'toggle' | 'select' | 'action'; label: string; active: boolean; onToggle: (active: boolean) => void; } interface ControlsGroupConfig { toggles: ControlsGroupToggle[]; } interface LegendGroupData { readonly name: string; readonly entries: ReadonlyArray<{ readonly value: string; readonly color: string; }>; /** Continuous (choropleth) groups carry a gradient ramp instead of discrete * entries — its active capsule renders `min ▭gradient▭ max` rather than dots. * Additive: only the map sets it; every other caller omits it and renders * unchanged. When set, `entries` is empty. */ readonly gradient?: { readonly min: number; readonly max: number; /** Resolved hex of the LOW (t=0) endpoint. For a single-colour ramp this is * the floored neutral (`mix(hue, base, RAMP_FLOOR)`); for an explicit * two-colour ramp it is the user's low colour. */ readonly low: string; /** Resolved hex of the HIGH (t=1) endpoint (the named hue). */ readonly high: string; }; } interface LegendConfig { groups: readonly LegendGroupData[]; position: LegendPosition; controls?: LegendControl[]; controlsGroup?: ControlsGroupConfig; mode: LegendMode; /** Title width in pixels — used for inline-with-title computation */ titleWidth?: number; /** Extra width (px) reserved after the pill inside an active capsule (e.g. for eye icon addon). Entries start after this offset. */ capsulePillAddonWidth?: number; /** When true, groups with no entries are still rendered as collapsed pills. Default: false (empty groups hidden). */ showEmptyGroups?: boolean; /** When true, INACTIVE sibling groups still render as collapsed pills next to * the active capsule (preview only — export still shows just the active * group). Lets the user click a sibling to switch the active group. Default * false (legacy: when one group is active the others are hidden). */ showInactivePills?: boolean; /** Where the controlsGroup is hosted. Default (undefined / 'inline') renders * the in-SVG gear exactly as before — every non-app consumer (Obsidian, * site, remark-family, CLI) is unaffected. When 'app', the controlsGroup is * dropped entirely (no gear, no reserved row): the app overlay strip owns the * controls, pinned to the top edge of the preview. App preview only; never * set on the export path. */ controlsHost?: 'app' | 'inline'; } interface LegendPalette { bg: string; surface: string; text: string; textMuted: string; primary?: string; } interface LegendPillLayout { groupName: string; x: number; y: number; width: number; height: number; isActive: boolean; } interface LegendEntryLayout { value: string; color: string; x: number; y: number; dotCx: number; dotCy: number; textX: number; textY: number; displayValue?: string; /** Full entry advance width (dot + gap + text + trail). Consumers draw a * transparent hit-rect of this width so the whole pill is hoverable, not * just the dot/text glyphs (legend-hover emphasis needs a filled target). */ width?: number; } interface LegendCapsuleLayout { groupName: string; x: number; y: number; width: number; height: number; pill: LegendPillLayout; entries: LegendEntryLayout[]; /** Overflow indicator when entries exceed max rows */ moreCount?: number; /** X offset where addon content (e.g. eye icon) can be placed — after pill, before entries */ addonX?: number; /** Continuous-ramp swatch (choropleth groups) drawn in place of entry dots: * `minText` | gradient rect | `maxText`, all vertically centred. */ gradient?: { rampX: number; rampY: number; rampW: number; rampH: number; /** Raw numeric ends (for the app's gradient-scrub: x → value). */ min: number; max: number; minText: string; minX: number; maxText: string; maxX: number; textY: number; /** Resolved hex endpoints (low = t0, high = t1); the renderer samples the * ramp between them via `valueRampStops`. */ low: string; high: string; }; } interface LegendControlLayout { id: string; x: number; y: number; width: number; height: number; icon: string; label?: string; exportBehavior: LegendControlExportBehavior; children?: Array<{ id: string; label: string; x: number; y: number; width: number; isActive?: boolean; }>; } interface ControlsGroupToggleLayout { id: string; label: string; active: boolean; dotCx: number; dotCy: number; textX: number; textY: number; } interface ControlsGroupLayout { x: number; y: number; width: number; height: number; expanded: boolean; /** The gear pill layout (collapsed or inside capsule) */ pill: { x: number; y: number; width: number; height: number; }; /** Toggle entries (only present when expanded) */ toggles: ControlsGroupToggleLayout[]; } interface LegendRowLayout { y: number; items: Array; } interface LegendLayout { /** Total computed height including all rows */ height: number; /** Total computed width */ width: number; /** Rows of legend elements (pills wrap to new rows on overflow) */ rows: LegendRowLayout[]; /** Active capsule layout (if any group is active) */ activeCapsule?: LegendCapsuleLayout; /** Control layouts (right-aligned) */ controls: LegendControlLayout[]; /** All pill layouts (collapsed groups) */ pills: LegendPillLayout[]; /** Controls group layout (gear pill / capsule) */ controlsGroup?: ControlsGroupLayout; } interface LegendHandle { setState: (state: LegendState) => void; destroy: () => void; getHeight: () => number; getLayout: () => LegendLayout; } type D3Sel = Selection; /** A parsed emphasis directive: which dual, and the names it lists. */ interface EmphasisDirective { readonly kind: 'highlight' | 'dim'; readonly names: readonly string[]; /** * True when the author used no comma, so `names` is a *guess* — `dim Ship * Provisions` is one two-word element far more often than two one-word ones. * Resolution tries the whole phrase first and only falls back to these * tokens, which means a comma is never required for the common single-name * case but always disambiguates when an author wants several. */ readonly ambiguous: boolean; /** The directive's argument text, verbatim — the whole-phrase candidate. */ readonly raw: string; readonly lineNumber: number; } type ExtendedChartType = 'sankey' | 'chord' | 'function' | 'scatter' | 'heatmap' | 'funnel'; interface ExtendedChartDataPoint { label: string; value: number; color?: string; lineNumber: number; } interface ParsedSankeyLink { source: string; target: string; value: number; color?: string; directed?: boolean; lineNumber: number; } interface ParsedFunction { name: string; expression: string; color?: string; lineNumber: number; } interface ParsedScatterPoint { name: string; x: number; y: number; size?: number; color?: string; category?: string; lineNumber: number; } interface ParsedHeatmapRow { label: string; values: number[]; lineNumber: number; } /** Fields shared by every extended data-chart. */ interface ParsedExtendedBase { title?: string; titleLineNumber?: number; series?: string; seriesLineNumber?: number; seriesNames?: string[]; seriesNameLineNumbers?: number[]; seriesNameColors?: (string | undefined)[]; data: ExtendedChartDataPoint[]; xlabel?: string; xlabelLineNumber?: number; ylabel?: string; ylabelLineNumber?: number; /** X-axis range — read by both function plots and scatter. */ xRange?: { min: number; max: number; }; noName?: boolean; noValue?: boolean; noPercent?: boolean; /** `fill` directive — shade the area below each curve (function charts), * parity with the `line` chart's bare `fill`. Opacity follows `fillMode`. */ fill?: boolean; /** §1.9 fill family: `'solid'` = full intent saturation, `'outline'` = * theme-background fill with color on the stroke. Absent ⇒ 25% tint. */ fillMode?: 'solid' | 'outline'; /** Cross-chart-type: when true, the renderer suppresses the chart title. */ noTitle?: boolean; /** Cross-chart-type: when true, the renderer suppresses the legend and the * vertical band it would occupy (#48). */ noLegend?: boolean; /** §1.9 `legend-inline`: title + series legend on one line (see ParsedChart). * Honoured by scatter/function among the extended charts (decision #50). */ legendInline?: boolean; /** §1.11 emphasis family: `highlight …` / `dim …`. Chart-level, * mutually exclusive, last-one-wins. Resolved against real element names at * render time via `resolveEmphasis`. */ emphasis?: EmphasisDirective; categoryColors?: Record; categoryLineNumbers?: Record; nodeColors?: Record; diagnostics: DgmoError[]; error: string | null; } interface ParsedSankey extends ParsedExtendedBase { type: 'sankey'; links?: ParsedSankeyLink[]; } interface ParsedChord extends ParsedExtendedBase { type: 'chord'; links?: ParsedSankeyLink[]; /** `layout arc|chord` override (#26). `arc` re-renders the same edges as a * linear arc; absent ⇒ the `chord` circular preset. */ layout?: 'arc' | 'chord'; } interface ParsedFunctionChart extends ParsedExtendedBase { type: 'function'; functions?: ParsedFunction[]; } interface ParsedScatter extends ParsedExtendedBase { type: 'scatter'; scatterPoints?: ParsedScatterPoint[]; sizelabel?: string; } interface ParsedHeatmap extends ParsedExtendedBase { type: 'heatmap'; heatmapRows?: ParsedHeatmapRow[]; columns?: string[]; rows?: string[]; } interface ParsedFunnel extends ParsedExtendedBase { type: 'funnel'; } /** What `parseExtendedChart` returns: discriminated on `type`. */ type ParsedExtendedChart = ParsedSankey | ParsedChord | ParsedFunctionChart | ParsedScatter | ParsedHeatmap | ParsedFunnel; /** * Parses extended chart content into a structured object. * * Format (colon-free): * ``` * scatter My Chart * xlabel Weight * * Alice 165, 60 * Bob 180, 85 * ``` */ declare function parseExtendedChart(content: string, palette?: PaletteColors): ParsedExtendedChart; /** * Extracts legend group data from standard chart types (multi-series line/bar). * Returns empty array if chart has no multi-series legend. */ declare function getSimpleChartLegendGroups(parsed: ParsedChart, colors: string[]): LegendGroupData[]; /** * Extracts legend group data from extended chart types. * Supports scatter (categories), chord (nodes), and function (series). */ declare function getExtendedChartLegendGroups(parsed: ParsedExtendedChart, colors: string[]): LegendGroupData[]; /** * Generates adaptive tick marks along a time axis. * Picks the right granularity (years, months, weeks, days, hours, minutes) * based on the domain span. * * Optional boundary parameters add ticks at exact data start/end: * - boundaryStart/boundaryEnd: numeric date values * - boundaryStartLabel/boundaryEndLabel: formatted labels for those dates */ declare function computeTimeTicks(domainMin: number, domainMax: number, scale: d3Scale.ScaleLinear, boundaryStart?: number, boundaryEnd?: number, boundaryStartLabel?: string, boundaryEndLabel?: string): { pos: number; label: string; }[]; /** * Participant types that can be declared via "Name is a type" syntax. * * The 0.16.0 trim retained only the types whose shapes carry semantic * weight at a glance: stick figure (actor), cylinder (database), * dashed cylinder (cache), horizontal pipe (queue), plus the default * rectangle. Any other type word falls back to `default`. */ type ParticipantType = 'default' | 'database' | 'actor' | 'queue' | 'cache'; /** * Branded participant identifier — a normalized name string that has * been minted through `addParticipant` and registered in the parser's * `participantMap`. Distinct from a raw display label or any other * `string`, so the type system catches "passed label where id expected" * at compile time. */ type ParticipantId = Brand; /** * A declared or inferred participant in the sequence diagram. */ interface SequenceParticipant { /** Internal identifier (e.g. "AuthService") */ readonly id: ParticipantId; /** Display label — first-seen casing/spacing of the name */ readonly label: string; /** Participant shape type */ readonly type: ParticipantType; /** Source line number (1-based) */ readonly lineNumber: number; /** Explicit layout position override (0-based from left, negative from right) */ readonly position?: number; /** Pipe-delimited tag metadata (e.g. `| role: Gateway`) */ readonly metadata?: Readonly>; } /** * A message between two participants. * * `kind: 'message'` is the discriminator for the SequenceElement union. * Pre-1.0 type addition — Epic 105 Story 105.17. */ interface SequenceMessage { readonly kind: 'message'; readonly from: ParticipantId; readonly to: ParticipantId; readonly label: string; readonly lineNumber: number; readonly async?: boolean; /** Pipe-delimited tag metadata (e.g. `| c: Caching`) */ readonly metadata?: Readonly>; } /** * A conditional or loop block in the sequence diagram. */ interface ElseIfBranch { readonly label: string; readonly children: readonly SequenceElement[]; readonly lineNumber: number; } interface SequenceBlock { readonly kind: 'block'; readonly type: 'if' | 'loop' | 'parallel'; readonly label: string; readonly children: readonly SequenceElement[]; readonly elseChildren: readonly SequenceElement[]; readonly elseIfBranches?: readonly ElseIfBranch[]; readonly elseLineNumber?: number; readonly lineNumber: number; } /** * A labeled horizontal divider between message phases. */ interface SequenceSection { readonly kind: 'section'; readonly label: string; readonly lineNumber: number; } /** * An annotation attached to a message, rendered as a folded-corner box. */ interface SequenceNote { readonly kind: 'note'; readonly text: string; readonly position: 'right' | 'left'; readonly participantId: ParticipantId; readonly lineNumber: number; readonly endLineNumber: number; } type SequenceElement = SequenceMessage | SequenceBlock | SequenceSection | SequenceNote; declare function isSequenceBlock(el: SequenceElement): el is SequenceBlock; declare function isSequenceNote(el: SequenceElement): el is SequenceNote; /** * A named group of participants rendered as a labeled box. */ interface SequenceGroup { readonly name: string; readonly participantIds: readonly ParticipantId[]; readonly lineNumber: number; /** Pipe-delimited tag metadata (e.g. `[Backend | t: Product]`) */ readonly metadata?: Readonly>; /** Whether this group is collapsed by default */ readonly collapsed?: boolean; } /** * Parsed result from a .dgmo sequence diagram. */ interface ParsedSequenceDgmo { readonly title: string | null; readonly titleLineNumber: number | null; readonly participants: readonly SequenceParticipant[]; readonly messages: readonly SequenceMessage[]; readonly elements: readonly SequenceElement[]; readonly groups: readonly SequenceGroup[]; readonly sections: readonly SequenceSection[]; readonly tagGroups: readonly TagGroup[]; readonly options: Readonly>; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } /** * Parse a .dgmo file with `chart: sequence` into a structured representation. */ declare function parseSequenceDgmo(content: string, palette?: PaletteColors): ParsedSequenceDgmo; /** * Detect whether raw content looks like a sequence diagram. * Used by the chart type inference logic. */ declare function looksLikeSequence(content: string): boolean; /** * Infer participant type from a name using the ordered rules table. * Returns 'default' if no rule matches. */ declare function inferParticipantType(name: string): ParticipantType; /** * Number of rules in the table. Exported for test assertions. */ declare const RULE_COUNT: number; interface DiagramNote { /** Author-typed node id/label the note attaches to. */ readonly ref: string; /** Body text (inline + indented lines, joined with `\n`). */ readonly body: string; /** Resolved hex accent (border + faded fill); default yellow if absent. */ readonly color?: string; readonly lineNumber: number; readonly endLineNumber: number; } type GraphShape = 'terminal' | 'process' | 'decision' | 'io' | 'subroutine' | 'document' | 'state' | 'pseudostate'; type GraphDirection = 'TB' | 'LR'; interface GraphNode { readonly id: string; readonly label: string; readonly shape: GraphShape; readonly color?: string; readonly group?: string; readonly lineNumber: number; /** * §1.4 tag metadata keyed by `tagAttrKey(group.name)` (state only — * decision #48). Absent on flowchart nodes and on state nodes in * diagrams that declare no tag groups. */ readonly metadata?: Readonly>; } interface GraphEdge { readonly source: string; readonly target: string; readonly label?: string; readonly color?: string; readonly lineNumber: number; } interface GraphGroup { readonly id: string; readonly label: string; readonly color?: string; readonly nodeIds: readonly string[]; readonly lineNumber: number; readonly collapsed?: boolean; } type GraphNote = DiagramNote; interface ParsedGraph { readonly type: 'flowchart' | 'state'; readonly title?: string; readonly titleLineNumber?: number; readonly direction: GraphDirection; readonly nodes: readonly GraphNode[]; readonly edges: readonly GraphEdge[]; readonly groups?: readonly GraphGroup[]; readonly notes?: readonly GraphNote[]; /** * Declared tag groups (state only — decision #48). Optional so the * flowchart parser, which has no tag channel, keeps its shape. */ readonly tagGroups?: readonly TagGroup[]; readonly options: Readonly>; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } type ChartType = string; interface DiagramSymbols { kind: ChartType; entities: string[]; /** * Map of alias-literal → canonical entity name, collected from * `Name as ` declarations in the document. Editor surfaces * both forms in autocomplete; selecting an alias inserts the alias * literal (the alias is input convenience, not a display name). */ aliases?: Record; } declare function parseFlowchart(content: string, palette?: PaletteColors): ParsedGraph; /** * Detect if content looks like a flowchart (without explicit `chart: flowchart` header). * Checks for shape delimiters combined with `->` arrows. * Avoids false-positives on sequence diagrams (which use bare names with `->`) */ declare function looksLikeFlowchart(content: string): boolean; /** * Extract node IDs (entities) from flowchart document text. * Used by the dgmo completion API for ghost hints and popup completions. */ declare function extractSymbols$3(docText: string): DiagramSymbols; declare function parseState(content: string, palette?: PaletteColors): ParsedGraph; /** * Detect if content looks like a state diagram (without explicit `chart: state` header). * Only matches if `[*]` token is present — too ambiguous to infer from bare names alone. */ declare function looksLikeState(content: string): boolean; /** * One rendered description line. `kind` controls horizontal placement and * whether the renderer draws a bullet glyph: * - `plain` — flush left at the description's left edge * - `bullet-first` — "•" drawn at the left edge, body text at the bullet column * - `bullet-cont` — body continuation at the bullet column (no glyph) * * Splitting first-line bullet rendering into separate text elements lets * continuation lines align exactly under the first word past the bullet, * regardless of font-width estimation drift. */ interface WrappedDescLine { text: string; kind: 'plain' | 'bullet-first' | 'bullet-cont'; } type NoteSide$1 = 'above' | 'below' | 'left' | 'right'; /** A note box positioned relative to its anchor node's center. */ interface NoteLayout { readonly x: number; readonly y: number; readonly width: number; readonly height: number; /** Which side of the node the box sits on (drives the connector). */ readonly side: NoteSide$1; /** Resolved hex accent (border + faded fill); default yellow if absent. */ readonly color?: string; readonly lines: readonly WrappedDescLine[]; readonly lineNumber: number; readonly endLineNumber: number; /** * When true the note is collapsed: the renderer draws a small badge at * the node corner instead of the floated box, and `x/y/width/height/side/ * lines` are unused. Collapsed notes reserve no layout space. */ readonly collapsed?: boolean; } interface LayoutNode { readonly id: string; readonly label: string; readonly shape: GraphShape; readonly color?: string; readonly group?: string; /** §1.4 tag metadata carried through from the parsed node (state only). */ readonly metadata?: Readonly>; readonly lineNumber: number; readonly x: number; readonly y: number; readonly width: number; readonly height: number; /** * A note floated beside this node. The shape keeps its natural dagre * position and dimensions (so its edges stay connected) — the note is * placed in adjacent space and the canvas bounds are expanded to fit * it. Absent on un-annotated nodes. */ readonly note?: NoteLayout; } interface LayoutEdge { readonly source: string; readonly target: string; readonly points: ReadonlyArray<{ readonly x: number; readonly y: number; }>; readonly label?: string; readonly lineNumber: number; } interface LayoutGroup { readonly id: string; readonly label: string; readonly color?: string; readonly lineNumber: number; readonly collapsed?: boolean; readonly x: number; readonly y: number; readonly width: number; readonly height: number; } interface LayoutOptions$1 { /** Map of group ID → number of child nodes (for collapsed groups) */ collapsedChildCounts?: Map; /** Original groups before collapse (includes collapsed ones) */ originalGroups?: readonly GraphGroup[]; /** * 1-based source line numbers of notes the user has collapsed. A * collapsed note renders as a corner badge and reserves no space. */ collapsedNotes?: ReadonlySet; } interface LayoutResult$1 { readonly nodes: readonly LayoutNode[]; readonly edges: readonly LayoutEdge[]; readonly groups: readonly LayoutGroup[]; readonly width: number; readonly height: number; } declare function layoutGraph(graph: ParsedGraph, options?: LayoutOptions$1): LayoutResult$1; declare function renderState(container: HTMLDivElement, graph: ParsedGraph, layout: LayoutResult$1, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }): void; declare function renderStateForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; interface StateCollapseResult { parsed: ParsedGraph; collapsedChildCounts: Map; originalGroups: readonly GraphGroup[]; } /** * Pure transform: returns a new ParsedGraph with collapsed groups * removed from the diagram content. * * - Children of collapsed groups removed from nodes * - Edges redirected: endpoints in collapsed groups → group ID * - Internal edges (both in same collapsed group) dropped * - Duplicate edges (same source, target, label) deduplicated * - Collapsed groups removed from groups[] (layout handles as nodes) */ declare function collapseStateGroups(parsed: ParsedGraph, collapsedGroups: Set): StateCollapseResult; type NoteSide = 'above' | 'below' | 'left' | 'right'; /** A resolved, placed note ready for the note-box drawer. */ interface PlacedNote { /** Box left, LOCAL to the node center (add node.x). Unused if collapsed. */ readonly x: number; /** Box top, LOCAL to the node center (add node.y). Unused if collapsed. */ readonly y: number; readonly width: number; readonly height: number; readonly side: NoteSide; /** Resolved hex accent (border + faded fill); default yellow if absent. */ readonly color?: string; readonly lines: readonly WrappedDescLine[]; readonly lineNumber: number; readonly endLineNumber: number; /** Collapsed → renderer draws a corner badge; box geometry is unused. */ readonly collapsed?: boolean; } type ClassModifier = 'abstract' | 'interface' | 'enum'; type MemberVisibility = 'public' | 'private' | 'protected'; type RelationshipType = 'extends' | 'implements' | 'composes' | 'aggregates' | 'depends' | 'associates'; interface ClassMember { readonly name: string; readonly type?: string; readonly params?: string; readonly visibility: MemberVisibility; readonly isStatic: boolean; readonly isMethod: boolean; readonly lineNumber: number; } interface ClassNode { readonly id: string; readonly name: string; readonly modifier?: ClassModifier; readonly color?: string; readonly members: readonly ClassMember[]; readonly lineNumber: number; } interface ClassRelationship { readonly source: string; readonly target: string; readonly type: RelationshipType; readonly label?: string; readonly lineNumber: number; } interface ParsedClassDiagram { readonly type: 'class'; readonly title?: string; readonly titleLineNumber?: number; readonly classes: readonly ClassNode[]; readonly relationships: readonly ClassRelationship[]; readonly options: Readonly>; /** Generic node notes (`note …`); resolved in layout. */ readonly notes?: readonly DiagramNote[]; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } declare function parseClassDiagram(content: string, palette?: PaletteColors): ParsedClassDiagram; /** * Detect if content looks like a class diagram without explicit `chart: class`. * Requires class-like patterns (capitalized names with modifiers or UML relationships). * Must not false-positive on flowcharts. */ declare function looksLikeClassDiagram(content: string): boolean; /** * Extract class names (entities) from class diagram document text. * Used by the dgmo completion API for ghost hints and popup completions. */ declare function extractSymbols$2(docText: string): DiagramSymbols; interface ClassLayoutNode extends ClassNode { readonly x: number; readonly y: number; readonly width: number; readonly height: number; readonly headerHeight: number; readonly fieldsHeight: number; readonly methodsHeight: number; /** A note floated beside this class (never moves the box). */ readonly note?: PlacedNote; } interface ClassLayoutOptions { /** * 1-based source line numbers of notes the user has collapsed. A * collapsed note renders as a corner badge and reserves no space. */ collapsedNotes?: ReadonlySet; } interface ClassLayoutEdge { readonly source: string; readonly target: string; readonly type: RelationshipType; readonly points: ReadonlyArray<{ readonly x: number; readonly y: number; }>; readonly label?: string; readonly lineNumber: number; } interface ClassLayoutResult { readonly nodes: readonly ClassLayoutNode[]; readonly edges: readonly ClassLayoutEdge[]; readonly width: number; readonly height: number; } declare function layoutClassDiagram(parsed: ParsedClassDiagram, options?: ClassLayoutOptions): ClassLayoutResult; declare function renderClassDiagram(container: HTMLDivElement, parsed: ParsedClassDiagram, layout: ClassLayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, legendActive?: boolean | null, exportMode?: boolean): void; declare function renderClassDiagramForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; type ERConstraint = 'pk' | 'fk' | 'unique' | 'nullable'; type ERCardinality = '1' | '*' | '?'; interface ERColumn { readonly name: string; readonly type?: string; readonly constraints: readonly ERConstraint[]; readonly lineNumber: number; } interface ERTable { readonly id: string; readonly name: string; readonly color?: string; readonly columns: readonly ERColumn[]; readonly metadata: Readonly>; readonly lineNumber: number; } interface ERRelationship { readonly source: string; readonly target: string; readonly cardinality: { readonly from: ERCardinality; readonly to: ERCardinality; }; readonly label?: string; readonly lineNumber: number; } interface ParsedERDiagram { readonly type: 'er'; readonly title?: string; readonly titleLineNumber?: number; readonly options: Readonly>; readonly tables: readonly ERTable[]; readonly relationships: readonly ERRelationship[]; readonly tagGroups: readonly TagGroup[]; /** Generic node notes (`note …`); resolved in layout. */ readonly notes?: readonly DiagramNote[]; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } declare function parseERDiagram(content: string, palette?: PaletteColors): ParsedERDiagram; /** * Detect if content looks like an ER diagram without explicit `er` first line. * Looks for indented lines with pk or fk constraint keywords. */ declare function looksLikeERDiagram(content: string): boolean; /** * Extract table names (entities) and ER keywords from document text. * Used by the dgmo completion API for ghost hints and popup completions. */ declare function extractSymbols$1(docText: string): DiagramSymbols; interface ERLayoutNode extends ERTable { readonly x: number; readonly y: number; readonly width: number; readonly height: number; readonly headerHeight: number; readonly columnsHeight: number; /** A note floated beside this table (never moves the box). */ readonly note?: PlacedNote; } interface ERLayoutOptions { /** 1-based source lines of notes the user collapsed (corner badge). */ collapsedNotes?: ReadonlySet; } interface ERLayoutEdge { readonly source: string; readonly target: string; readonly cardinality: { readonly from: string; readonly to: string; }; readonly points: ReadonlyArray<{ readonly x: number; readonly y: number; }>; readonly label?: string; readonly lineNumber: number; } interface ERLayoutResult { readonly nodes: readonly ERLayoutNode[]; readonly edges: readonly ERLayoutEdge[]; readonly width: number; readonly height: number; } declare function layoutERDiagram(parsed: ParsedERDiagram, options?: ERLayoutOptions): ERLayoutResult; declare function renderERDiagram(container: HTMLDivElement, parsed: ParsedERDiagram, layout: ERLayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, activeTagGroup?: string | null, /** When false, semantic role colors are suppressed and entities use a neutral color. */ semanticColorsActive?: boolean, exportMode?: boolean): void; declare function renderERDiagramForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; interface InlineSpan { text: string; bold?: boolean; italic?: boolean; code?: boolean; href?: string; } declare function parseInlineMarkdown(text: string): InlineSpan[]; declare function truncateBareUrl(url: string): string; /** * Reduce a name to its canonical key for equality comparison. * * Idempotent: `normalizeName(normalizeName(x)) === normalizeName(x)`. * * The returned key is for equality only — never display it. Callers * that need to render a name should use the `displayLabel` field of * the `NameEntry` returned by `getOrCreateName`. */ declare function normalizeName(input: string): string; /** * Reduce a name to its display form: NFC normalize and trim only. * * Casing AND internal whitespace are preserved verbatim — the spec * says "first-seen casing/spacing wins for display" (ADR-002), so a * double space typed by the user survives into the rendered label. * Renderers may collapse it for layout, but the source-of-truth is * what the user typed. * * Two inputs that share the same `normalizeName(...)` key but have * different `displayName(...)` values are a "merge" — surfaced via * the `NAME_MERGED` diagnostic. */ declare function displayName(input: string): string; /** * One entity, identified by its normalized key. * * Parsers either use this shape directly in their entity Map or * compose it into a richer per-chart node type. Equality MUST use * only `normalizedKey`; rendering MUST use only `displayLabel`. */ interface NameEntry { /** Output of `normalizeName(input)` — the lookup key. */ normalizedKey: string; /** First-seen casing/spacing — what gets rendered. */ displayLabel: string; /** 1-based source line where the name was first declared. */ declaredLine: number; } /** * Result of an entity insertion attempt. * * `created` is true on first sighting. `merged` is present iff the * input collided with an existing entry AND the displayed forms * differ — that is the case worth reporting via `NAME_MERGED`. * Identical re-declarations produce neither `created` nor `merged`. */ interface GetOrCreateNameResult { entry: NameEntry; created: boolean; merged?: { existingLine: number; existingDisplay: string; incomingDisplay: string; }; } /** * Insert-or-fetch helper for `Map` stores. * * Parsers that need a richer node type (e.g. flowchart's `Node` * carries shape + edges) should wrap this helper: call it for the * normalization + merge-detection bookkeeping, then store the result * in their own `Map`. * * When an `aliasStore` is provided, alias resolution runs FIRST: an * exact-match (case-sensitive) hit returns the bound canonical entry * untouched (the alias literal does NOT contribute to display or * merge bookkeeping). Misses fall through to UNH normalization. */ declare function getOrCreateName(input: string, store: Map, lineNumber: number, aliasStore?: AliasMap): GetOrCreateNameResult; /** alias literal → bound canonical entry. Exact-match, case-sensitive. */ type AliasMap = Map; interface OrgLayoutNode { readonly id: string; readonly label: string; readonly metadata: Readonly>; /** Original (unfiltered) metadata — used for tag-based hover dimming even when the group is hidden */ readonly tagMetadata: Readonly>; readonly isContainer: boolean; readonly lineNumber: number; readonly color?: string; readonly x: number; readonly y: number; readonly width: number; readonly height: number; /** Count of hidden descendants when this node is collapsed */ readonly hiddenCount?: number; /** True if node has children (expanded or collapsed) — drives toggle UI */ readonly hasChildren?: boolean; } interface OrgLayoutEdge { readonly sourceId: string; readonly targetId: string; readonly points: ReadonlyArray<{ readonly x: number; readonly y: number; }>; } interface OrgContainerBounds { readonly nodeId: string; readonly label: string; readonly lineNumber: number; readonly color?: string; readonly metadata: Readonly>; /** Original (unfiltered) metadata — used for tag-based hover dimming even when the group is hidden */ readonly tagMetadata: Readonly>; readonly x: number; readonly y: number; readonly width: number; readonly height: number; readonly labelHeight: number; /** Count of hidden descendants when this container is collapsed */ readonly hiddenCount?: number; /** True if container has children (expanded or collapsed) — drives toggle UI */ readonly hasChildren?: boolean; } interface OrgLegendEntry { readonly value: string; readonly color: string; } interface OrgLegendGroup { readonly name: string; readonly alias?: string; readonly entries: readonly OrgLegendEntry[]; readonly x: number; readonly y: number; readonly width: number; readonly height: number; readonly minifiedWidth: number; readonly minifiedHeight: number; } interface OrgLayoutResult { readonly nodes: readonly OrgLayoutNode[]; readonly edges: readonly OrgLayoutEdge[]; readonly containers: readonly OrgContainerBounds[]; readonly legend: readonly OrgLegendGroup[]; readonly width: number; readonly height: number; /** * How far every node, container and edge point was pushed DOWN to leave room * for a legend row drawn inside the diagram — 0 when no group is visible. * A renderer that draws the legend somewhere else (the app pins it above the * scaled diagram at native size) takes this back, so it must read the shift * that was actually applied rather than assume one (#325). */ readonly legendShift: number; } declare function layoutOrg(parsed: ParsedOrg, hiddenCounts?: Map, activeTagGroup?: string | null, hiddenAttributes?: Set, expandAllLegend?: boolean): OrgLayoutResult; interface CollapsedOrgResult { /** ParsedOrg with collapsed subtrees pruned (deep-cloned, never mutates original) */ parsed: ParsedOrg; /** nodeId → count of hidden descendants */ hiddenCounts: Map; } interface AncestorInfo { id: string; label: string; lineNumber: number; color?: string; metadata: Record; isContainer: boolean; } interface FocusOrgResult { /** ParsedOrg with only the focused subtree as the single root */ parsed: ParsedOrg; /** Ancestor path from original root → parent of focused node (top-down order) */ ancestorPath: AncestorInfo[]; } declare function collapseOrgTree(original: ParsedOrg, collapsedIds: Set): CollapsedOrgResult; /** * Extract a subtree rooted at `focusNodeId`, returning the focused tree * and the ancestor breadcrumb path. Returns null if the node is not found. */ declare function focusOrgTree(original: ParsedOrg, focusNodeId: string): FocusOrgResult | null; declare function renderOrg(container: HTMLDivElement, parsed: ParsedOrg, layout: OrgLayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, activeTagGroup?: string | null, hiddenAttributes?: Set, ancestorPath?: AncestorInfo[], exportMode?: boolean): void; declare function renderOrgForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; /** @deprecated Use `TagEntry` from `utils/tag-groups` */ type KanbanTagEntry = TagEntry; /** @deprecated Use `TagGroup` from `utils/tag-groups` */ type KanbanTagGroup = TagGroup; interface KanbanCard { readonly id: string; readonly title: string; readonly tags: Readonly>; readonly details: readonly string[]; readonly lineNumber: number; readonly endLineNumber: number; readonly color?: string; } interface KanbanColumn { readonly id: string; readonly name: string; readonly wipLimit?: number; readonly color?: string; readonly collapsed?: boolean; readonly metadata?: Readonly>; readonly cards: readonly KanbanCard[]; readonly lineNumber: number; } interface ParsedKanban { readonly type: 'kanban'; readonly title?: string; readonly titleLineNumber?: number; readonly columns: readonly KanbanColumn[]; readonly tagGroups: readonly KanbanTagGroup[]; readonly options: Readonly>; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } declare function parseKanban(content: string, palette?: PaletteColors): ParsedKanban; /** * Compute new file content after moving a card to a different position. * * @param content - original file content string * @param parsed - parsed kanban board * @param cardId - id of the card to move * @param targetColumnId - id of the destination column * @param targetIndex - position within target column (0 = first card) * @returns new content string, or null if move is invalid */ declare function computeCardMove(content: string, parsed: ParsedKanban, cardId: string, targetColumnId: string, targetIndex: number): string | null; /** * Move a card to the Archive section at the end of the file. * Creates `== Archive ==` if it doesn't exist. * * @returns new content string, or null if the card is not found */ declare function computeCardArchive(content: string, parsed: ParsedKanban, cardId: string): string | null; /** Check if a column name is the archive column (case-insensitive). */ declare function isArchiveColumn(name: string): boolean; interface KanbanInteractiveOptions { onNavigateToLine?: (line: number) => void; exportDims?: { width: number; height: number; }; activeTagGroup?: string | null; currentSwimlaneGroup?: string | null; onSwimlaneChange?: (group: string | null) => void; collapsedLanes?: Set; collapsedColumns?: Set; compactMeta?: boolean; exportMode?: boolean; } declare function renderKanban(container: HTMLElement, parsed: ParsedKanban, palette: PaletteColors, isDark: boolean, options?: KanbanInteractiveOptions): void; declare function renderKanbanForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; /** @deprecated Use `TagEntry` from `utils/tag-groups` */ type C4TagEntry = TagEntry; /** @deprecated Use `TagGroup` from `utils/tag-groups` */ type C4TagGroup = TagGroup; type C4ElementType = 'person' | 'system' | 'container' | 'component'; type C4Shape = 'default' | 'database' | 'cache' | 'queue' | 'cloud' | 'external'; type C4ArrowType = 'sync' | 'async' | 'bidirectional' | 'bidirectional-async'; interface C4Relationship { readonly target: string; readonly label?: string; readonly technology?: string; readonly arrowType: C4ArrowType; readonly lineNumber: number; } interface C4Group { readonly name: string; readonly children: readonly C4Element[]; /** * Authored collapse marker (§1.8, decision #48): bare trailing * `collapsed` flag on the `[Group]` line (legacy: `collapsed: true`). * Parsed and exposed for consumers; the c4 layout does not yet fold * group boundaries. */ readonly collapsed?: boolean; readonly lineNumber: number; } interface C4Element { readonly name: string; readonly type: C4ElementType; readonly shape: C4Shape; readonly metadata: Readonly>; readonly description?: readonly string[]; readonly children: readonly C4Element[]; readonly groups: readonly C4Group[]; readonly relationships: readonly C4Relationship[]; readonly importPath?: string; readonly lineNumber: number; readonly sectionHeader?: 'containers' | 'components'; readonly sectionHeaderLineNumber?: number; } interface C4DeploymentNode { readonly name: string; readonly metadata: Readonly>; readonly shape: C4Shape; readonly children: readonly C4DeploymentNode[]; readonly containerRefs: readonly string[]; readonly lineNumber: number; } interface ParsedC4 { readonly title: string | null; readonly titleLineNumber: number | null; readonly options: Readonly>; /** * Resolved layout direction (§8.7). `direction-lr` / `direction-tb` are a * mutually-exclusive boolean pair (§1.9, last one wins). Defaults to 'TB', * which is the orientation C4 views have always rendered. */ readonly direction: 'LR' | 'TB'; readonly tagGroups: readonly TagGroup[]; readonly elements: readonly C4Element[]; readonly relationships: readonly C4Relationship[]; readonly deployment: readonly C4DeploymentNode[]; readonly diagnostics: readonly DgmoError[]; readonly error: string | null; } declare function parseC4(content: string, palette?: PaletteColors): ParsedC4; interface C4LayoutNode { readonly id: string; readonly name: string; readonly type: 'person' | 'system' | 'container' | 'component'; readonly description?: string; readonly metadata: Readonly>; readonly lineNumber: number; readonly color?: string; readonly shape?: C4Shape; readonly technology?: string; readonly drillable?: boolean; readonly importPath?: string; readonly x: number; readonly y: number; readonly width: number; readonly height: number; } interface C4LayoutEdge { readonly source: string; readonly target: string; readonly arrowType: C4ArrowType; readonly label?: string; readonly technology?: string; readonly lineNumber: number; readonly points: ReadonlyArray<{ readonly x: number; readonly y: number; }>; } interface C4LegendEntry { readonly value: string; readonly color: string; } interface C4LegendGroup { readonly name: string; readonly entries: readonly C4LegendEntry[]; readonly x: number; readonly y: number; readonly width: number; readonly height: number; } interface C4LayoutBoundary { readonly label: string; readonly typeLabel: string; readonly lineNumber: number; readonly x: number; readonly y: number; readonly width: number; readonly height: number; } interface C4LayoutResult { readonly nodes: readonly C4LayoutNode[]; readonly edges: readonly C4LayoutEdge[]; readonly legend: readonly C4LegendGroup[]; readonly boundary?: C4LayoutBoundary; readonly groupBoundaries: readonly C4LayoutBoundary[]; readonly width: number; readonly height: number; } interface ContextRelationship { sourceName: string; targetName: string; label?: string; technology?: string; arrowType: C4ArrowType; lineNumber: number; } /** * Roll up container/component-level relationships to system-to-system edges. * - Skips internal relationships (same top-level ancestor). * - Deduplicates: same source→target pair keeps only one (first seen). * - Explicit system-level relationships override rolled-up ones. */ declare function rollUpContextRelationships(parsed: ParsedC4): ContextRelationship[]; declare function layoutC4Context(parsed: ParsedC4, activeTagGroup?: string | null): C4LayoutResult; /** * Layout containers within a specific system, plus external elements * that have relationships with those containers. */ declare function layoutC4Containers(parsed: ParsedC4, systemName: string, activeTagGroup?: string | null): C4LayoutResult; /** * Layout components within a specific container, plus external elements * that have relationships with those components. */ declare function layoutC4Components(parsed: ParsedC4, systemName: string, containerName: string, activeTagGroup?: string | null): C4LayoutResult; /** * Layout a C4 deployment diagram. * * Infrastructure nodes become boundary boxes (nested). * Container refs inside them become cards. * Edges are drawn between referenced containers that have relationships. */ declare function layoutC4Deployment(parsed: ParsedC4, activeTagGroup?: string | null): C4LayoutResult; declare function renderC4Context(container: HTMLDivElement, parsed: ParsedC4, layout: C4LayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, activeTagGroup?: string | null, exportMode?: boolean): void; declare function renderC4ContextForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; /** * Render a C4 container-level diagram showing containers inside a system boundary * with external elements outside. */ declare function renderC4Containers(container: HTMLDivElement, parsed: ParsedC4, layout: C4LayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, activeTagGroup?: string | null, exportMode?: boolean): void; declare function renderC4ContainersForExport(content: string, systemName: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; declare function renderC4ComponentsForExport(content: string, systemName: string, containerName: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; /** * Render a C4 deployment diagram interactively. * Reuses the container renderer — infrastructure boundaries are rendered * as group boundaries and container refs as cards (same visual pattern). */ declare function renderC4Deployment(container: HTMLDivElement, parsed: ParsedC4, layout: C4LayoutResult, palette: PaletteColors, isDark: boolean, onClickItem?: (lineNumber: number) => void, exportDims?: { width?: number; height?: number; }, activeTagGroup?: string | null, exportMode?: boolean): void; /** * Export convenience function for deployment diagrams. */ declare function renderC4DeploymentForExport(content: string, theme: 'light' | 'dark' | 'transparent', palette: PaletteColors): string; interface BLNode { readonly label: string; readonly lineNumber: number; readonly metadata: Readonly>; readonly description?: readonly string[]; /** Numeric measure lifted from `heat: X` metadata (mirror of map's * `region.value`). Drives the heat ramp / choropleth tinting. */ readonly value?: number; } interface BLEdge { readonly source: string; readonly target: string; readonly label?: string; readonly bidirectional: boolean; readonly lineNumber: number; readonly metadata: Readonly>; } interface BLGroup { readonly label: string; readonly children: readonly string[]; readonly lineNumber: number; readonly metadata: Readonly>; readonly parentGroup?: string; } interface ParsedBoxesAndLines { readonly type: 'boxes-and-lines'; readonly title: string | null; readonly titleLineNumber: number | null; readonly nodes: readonly BLNode[]; readonly edges: readonly BLEdge[]; readonly groups: readonly BLGroup[]; readonly tagGroups: readonly TagGroup[]; readonly options: Readonly>; /** Generic node notes (`note …`); resolved in layout. */ readonly notes?: readonly DiagramNote[]; readonly initialHiddenTagValues: ReadonlyMap>; readonly direction: 'LR' | 'TB'; /** `heat