diago

    A diagram toolkit for MoonBit with Dagre, ELK, and Railway layout engines, rendering SVG, ASCII, and Unicode outputs.

    graph
    Download zip
    Author
    Version
    0.3.5
    License
    Apache-2.0
    Last updated
    1 hour ago
    Downloads
    19K

    #Diago

    Diago is a diagram toolkit for MoonBit. It supports a D2-compatible text format and renders diagrams through multiple layout engines.

    #Overview

    This repository contains:

    • A backend-independent library facade (Milky2018/diago) for parsing, layout, and rendering
    • A native filesystem adapter (Milky2018/diago/fs) for file loading and relative imports
    • A CLI (cmd/diago) with explicit subcommands (render, fmt, validate, layout, themes, version)
    • A WASM-based playground (web/) deployed via GitHub Pages
    • A Node.js Markdown package (markdown/) for markdown-it, remark, and VitePress
    • Multiple layout engines: dagre, elk, and railway

    #Installation

    moon update moon build

    #Quick Start

    moon run cmd/diago -- render diagram.txt

    #Library API

    The root package is supported on all MoonBit targets. It accepts source text and never reads the local filesystem implicitly:

    ///|
    test {
    let ascii = @diago.compile(
    "a -> b",
    options=@diago.CompileOptions::new().with_output_mode(Ascii),
    )
    inspect(
    ascii,
    content=(
    #|+----+
    #|| a |
    #|| |
    #|+----+
    #| |
    #|+----+
    #|| b |
    #|| |
    #|+----+
    #|
    ),
    )
    }

    Imports are explicit and backend-independent through ParseOptions::with_import_resolver. Editors can call get_syntax_tokens on every target to obtain error-tolerant Unicode code-point ranges for comments, strings, literals, keywords, identifiers, operators, and punctuation.

    #Unsupported D2 features

    Diago does not currently support LaTeX labels (|tex or |latex) or sketch rendering (style.sketch, vars.d2-config.sketch, or the sketch render option). These inputs return UnsupportedFeature instead of silently falling back to plain text or ordinary SVG rendering. They can be reconsidered when backend-independent community implementations are available for all MoonBit targets.

    Native applications can opt into local file access through the filesystem adapter:

    ///|
    async fn main {
    let svg = @diago_fs.compile_file("diagram.d2")
    }

    compile_file and parse_file use moonbitlang/async/fs, resolve imports relative to the input file, and preserve a custom resolver supplied by the caller.

    #Markdown package

    The diago npm package renders exact lowercase diago fences to inline SVG at build time. It is Node.js 20+ and ESM-only and bundles the matching Diago Wasm:

    import MarkdownIt from 'markdown-it' import diago from 'diago/markdown-it' const md = new MarkdownIt().use(diago) const html = md.render('```diago\na -> b\n```', { path: 'docs/example.md', })

    The package also exports diago/remark and diago/vitepress. Failed diagrams remain code fences and produce structured diagnostics. File imports, sketch, and LaTeX are not supported in Markdown fences. Only use the adapters with trusted project-authored Markdown: generated inline SVG is active HTML and is not sanitized by the package. See markdown/README.md for the complete interface and CSP notes.

    #CLI

    Show help:

    moon run cmd/diago -- --help

    Common usage:

    # Render SVG (default output: input.svg) moon run cmd/diago -- render diagram.txt moon run cmd/diago -- render diagram.txt diagram.svg moon run cmd/diago -- render diagram.txt --output diagram.svg # Choose layout engine moon run cmd/diago -- render --layout elk diagram.txt diagram.svg moon run cmd/diago -- render -l dagre diagram.txt diagram.svg # ASCII / Unicode text moon run cmd/diago -- render --format ascii diagram.txt --output diagram.ascii.txt moon run cmd/diago -- render --format unicode diagram.txt --output diagram.unicode.txt # Format / validate moon run cmd/diago -- fmt diagram.txt moon run cmd/diago -- fmt --check diagram.txt moon run cmd/diago -- validate diagram.txt # Watch mode (rebuilds output on file changes) moon run cmd/diago -- render --watch diagram.txt # Introspection moon run cmd/diago -- layout moon run cmd/diago -- layout elk moon run cmd/diago -- themes moon run cmd/diago -- version

    #Example

    Create a file example.txt:

    server: Web Server database: Database { shape: cylinder } cache: Cache { shape: oval } server -> database: queries server -> cache: reads cache -> database: fallback

    Compile it:

    moon run cmd/diago -- render example.txt example.svg

    #Pipeline

    At a high level:

    Source → Lexer → Parser → AST → IR → Graph → Layout (dagre/elk/railway) → Render (SVG/ASCII/Unicode)

    #Tests

    moon check --target all --deny-warn moon test --target all moon build cmd/diago --target native --release moon build cmd/wasm --target wasm --release node scripts/wasm_smoke.mjs _build/wasm/release/build/cmd/wasm/wasm.wasm npm ci --prefix web npm test --prefix web npm ci --prefix markdown npm test --prefix markdown npm run test:corpus --prefix markdown npm run test:package --prefix markdown

    #License

    Apache-2.0 (see LICENSE).

    DiagoError

    pub(all) suberror DiagoError {
    ParseError(String)
    IOError(String)
    IrError(String)
    GraphError(String)
    LayoutError(String)
    RenderError(String)
    ConfigError(String)
    TargetError(String)
    UnsupportedFeature(String)
    } derive(Eq,
    Debug
    )

    DiagoError::equal

    #deprecated("`DiagoError::equal` is deprecated, use `Eq::equal` instead.")
    fn DiagoError::equal(DiagoError, DiagoError) -> Bool

    DiagoError::not_equal

    #deprecated("`DiagoError::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn DiagoError::not_equal(x : DiagoError, y : DiagoError) -> Bool

    DiagoError::to_repr

    #deprecated("`DiagoError::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn DiagoError::to_repr(DiagoError) ->
    Repr

    CompileOptions

    pub struct CompileOptions {
    output_mode : OutputMode
    layout_engine : LayoutEngine
    direction :
    Direction

    target_spec : String?
    layout_plugin : LayoutPlugin?
    route_plugin : RoutePlugin?
    parse_options : ParseOptions
    theme_name : String?
    dark_theme_id : Int?
    sketch : Bool?
    pad : Double?
    center : Bool?
    theme_overrides :
    ThemeOverrides
    ?
    dark_theme_overrides :
    ThemeOverrides
    ?
    scale : Double?
    no_xml_tag : Bool?
    salt : String?
    omit_version : Bool?
    }

    CompileOptions::new

    CompileOptions::with_center

    fn CompileOptions::with_center(self : CompileOptions, center : Bool?) -> CompileOptions

    CompileOptions::with_dark_theme_id

    fn CompileOptions::with_dark_theme_id(self : CompileOptions, dark_theme_id : Int?) -> CompileOptions

    CompileOptions::with_dark_theme_overrides

    fn CompileOptions::with_dark_theme_overrides(self : CompileOptions, dark_theme_overrides :
    ThemeOverrides
    ?) -> CompileOptions

    CompileOptions::with_direction

    CompileOptions::with_layout_engine

    fn CompileOptions::with_layout_engine(self : CompileOptions, layout_engine : LayoutEngine) -> CompileOptions

    CompileOptions::with_layout_plugin

    fn CompileOptions::with_layout_plugin(self : CompileOptions, layout_plugin : LayoutPlugin?) -> CompileOptions

    CompileOptions::with_no_xml_tag

    fn CompileOptions::with_no_xml_tag(self : CompileOptions, no_xml_tag : Bool?) -> CompileOptions

    CompileOptions::with_omit_version

    fn CompileOptions::with_omit_version(self : CompileOptions, omit_version : Bool?) -> CompileOptions

    CompileOptions::with_output_mode

    fn CompileOptions::with_output_mode(self : CompileOptions, output_mode : OutputMode) -> CompileOptions

    CompileOptions::with_pad

    fn CompileOptions::with_pad(self : CompileOptions, pad : Double?) -> CompileOptions

    CompileOptions::with_parse_options

    fn CompileOptions::with_parse_options(self : CompileOptions, parse_options : ParseOptions) -> CompileOptions

    CompileOptions::with_route_plugin

    fn CompileOptions::with_route_plugin(self : CompileOptions, route_plugin : RoutePlugin?) -> CompileOptions

    CompileOptions::with_salt

    fn CompileOptions::with_salt(self : CompileOptions, salt : String?) -> CompileOptions

    CompileOptions::with_scale

    fn CompileOptions::with_scale(self : CompileOptions, scale : Double?) -> CompileOptions

    CompileOptions::with_sketch

    fn CompileOptions::with_sketch(self : CompileOptions, sketch : Bool?) -> CompileOptions

    CompileOptions::with_target_spec

    fn CompileOptions::with_target_spec(self : CompileOptions, target_spec : String?) -> CompileOptions

    CompileOptions::with_theme_name

    fn CompileOptions::with_theme_name(self : CompileOptions, theme_name : String?) -> CompileOptions

    CompileOptions::with_theme_overrides

    CompletionItem

    pub struct CompletionItem {
    label : String
    kind : CompletionKind
    detail : String
    insert_text : String
    } derive(Eq,
    Debug
    )

    CompletionItem::equal

    #deprecated("`CompletionItem::equal` is deprecated, use `Eq::equal` instead.")
    fn CompletionItem::equal(CompletionItem, CompletionItem) -> Bool

    CompletionItem::not_equal

    #deprecated("`CompletionItem::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn CompletionItem::not_equal(x : CompletionItem, y : CompletionItem) -> Bool

    CompletionItem::to_repr

    #deprecated("`CompletionItem::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn CompletionItem::to_repr(CompletionItem) ->
    Repr

    CompletionKind

    pub(all) enum CompletionKind {
    Keyword
    Style
    Shape
    Value
    } derive(Eq,
    Debug
    )

    CompletionKind::equal

    #deprecated("`CompletionKind::equal` is deprecated, use `Eq::equal` instead.")
    fn CompletionKind::equal(CompletionKind, CompletionKind) -> Bool

    CompletionKind::not_equal

    #deprecated("`CompletionKind::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn CompletionKind::not_equal(x : CompletionKind, y : CompletionKind) -> Bool

    CompletionKind::to_repr

    #deprecated("`CompletionKind::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn CompletionKind::to_repr(CompletionKind) ->
    Repr

    LayoutEngine

    pub(all) enum LayoutEngine {
    Auto
    Dagre
    Elk
    Railway
    } derive(Eq,
    Debug
    )

    LayoutEngine::equal

    #deprecated("`LayoutEngine::equal` is deprecated, use `Eq::equal` instead.")
    fn LayoutEngine::equal(LayoutEngine, LayoutEngine) -> Bool

    LayoutEngine::not_equal

    #deprecated("`LayoutEngine::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn LayoutEngine::not_equal(x : LayoutEngine, y : LayoutEngine) -> Bool

    LayoutEngine::to_repr

    #deprecated("`LayoutEngine::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn LayoutEngine::to_repr(LayoutEngine) ->
    Repr

    OutputMode

    pub(all) enum OutputMode {
    Svg
    Ascii
    Unicode
    } derive(Eq,
    Debug
    )

    OutputMode::equal

    #deprecated("`OutputMode::equal` is deprecated, use `Eq::equal` instead.")
    fn OutputMode::equal(OutputMode, OutputMode) -> Bool

    OutputMode::not_equal

    #deprecated("`OutputMode::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn OutputMode::not_equal(x : OutputMode, y : OutputMode) -> Bool

    OutputMode::to_repr

    #deprecated("`OutputMode::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn OutputMode::to_repr(OutputMode) ->
    Repr

    ParseOptions

    pub struct ParseOptions {
    import_resolver :
    ImportResolver
    ?
    }

    ParseOptions::new

    ParseOptions::with_import_resolver

    fn ParseOptions::with_import_resolver(_self : ParseOptions, import_resolver :
    ImportResolver
    ?) -> ParseOptions

    SyntaxToken

    pub struct SyntaxToken {
    start : Int
    end : Int
    kind : SyntaxTokenKind
    } derive(Eq,
    Debug
    )

    A highlighted source range.

    start and end are zero-based Unicode code point offsets. The range is half-open: it includes start and excludes end.

    SyntaxToken::equal

    #deprecated("`SyntaxToken::equal` is deprecated, use `Eq::equal` instead.")
    fn SyntaxToken::equal(SyntaxToken, SyntaxToken) -> Bool

    SyntaxToken::not_equal

    #deprecated("`SyntaxToken::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn SyntaxToken::not_equal(x : SyntaxToken, y : SyntaxToken) -> Bool

    SyntaxToken::to_repr

    #deprecated("`SyntaxToken::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn SyntaxToken::to_repr(SyntaxToken) ->
    Repr

    SyntaxTokenKind

    pub(all) enum SyntaxTokenKind {
    Comment
    String
    Number
    Boolean
    Keyword
    Identifier
    Operator
    Punctuation
    } derive(Eq,
    Debug
    )

    A lexical category used by source editors.

    SyntaxTokenKind::equal

    #deprecated("`SyntaxTokenKind::equal` is deprecated, use `Eq::equal` instead.")
    fn SyntaxTokenKind::equal(SyntaxTokenKind, SyntaxTokenKind) -> Bool

    SyntaxTokenKind::not_equal

    #deprecated("`SyntaxTokenKind::not_equal` is deprecated, use `Eq::not_equal` instead.")
    fn SyntaxTokenKind::not_equal(x : SyntaxTokenKind, y : SyntaxTokenKind) -> Bool

    SyntaxTokenKind::to_repr

    #deprecated("`SyntaxTokenKind::to_repr` is deprecated, use `@moonbitlang/core/debug.Debug::to_repr` instead.")
    fn SyntaxTokenKind::to_repr(SyntaxTokenKind) ->
    Repr

    compile

    fn compile(source : String, options? : CompileOptions) -> String raise DiagoError

    compile_diagram

    fn compile_diagram(source : String, options? : CompileOptions) ->
    Diagram
    raise DiagoError

    get_board_path_at_position

    fn get_board_path_at_position(source : String, line : Int, column : Int) -> Array[String]

    get_completion_items

    fn get_completion_items(source : String, line : Int, column : Int) -> Array[CompletionItem]

    get_ref_ranges

    fn get_ref_ranges(source : String, key : String, board_path? : Array[String], options? : ParseOptions) -> Array[
    Range
    ] raise DiagoError

    get_syntax_tokens

    fn get_syntax_tokens(source : String) -> Array[SyntaxToken]

    Tokenize Diago source for syntax highlighting.

    The result is available even when the source is incomplete or contains syntax errors.

    parse

    fn parse(source : String, options? : ParseOptions) ->
    Map
    raise DiagoError