# Vendored third-party crate.
#
# Upstream:  warpdotdev/mermaid-to-svg (MIT) —
#            https://github.com/warpdotdev/mermaid-to-svg
#            rev 40cecf2be376e47e15053eadbfb782a531777420
#
# Why vendored (not a crates.io pin): the engine renders untrusted model output
# and is a young dependency. Vendoring gives a full audit surface and immunity to
# upstream yanks for the hardened CLI binary. Warp's engine delegates layout
# to a Rust port of dagre.js (the same algorithm mermaid.js uses), which fixes
# the cyclic-flowchart back-edge mis-routing of the previous engine. See
# crates/codegen/xai-grok-mermaid.
#
# ============================================================================
# VENDORING NOTES — single source of truth. Re-apply / re-bless ALL of the
# following on every upstream upgrade:
# ============================================================================
#
# Local modifications to the upstream source:
#  1. NOT VENDORED: `src/bin/render_mermaid.rs` (CLI binary). Its `[[bin]]` and
#     the dev-only deps (insta/rust-embed/resvg/roxmltree/image/anyhow/serde*)
#     are dropped — `xai-grok-mermaid` rasterizes the SVG itself with the
#     workspace `resvg`, so this is used as an SVG generator only.
#  2. NOT VENDORED: every `*_tests.rs` snapshot/fixture test plus `reference_svg`
#     and `fixtures` (they `include`/embed un-vendored `samples/` assets and need
#     the dropped dev-deps). Their `#[cfg(test)] #[path = "..."] mod tests;`
#     declarations and the `pub mod fixtures;` / `mod reference_svg;` lines were
#     removed from the kept sources. The two *in-source* `mod tests` blocks
#     (`src/lib.rs` public-API smoke tests, `src/mermaid_port/dagre_layout_port.rs`
#     unit tests) use no dev-deps and are kept; `[lib] doctest = false`. One
#     LOCAL ADDITION to the kept `src/lib.rs` tests: `test_simple_c4_diagram`
#     (marked in-source), filling the only dispatched diagram type that upstream
#     left without a `test_simple_*` smoke test.
#  3. HERMETIC PATCH (src/mermaid_port/mod.rs): `is_enabled()` returns `false`
#     unconditionally. Upstream read the `MERMAID_TO_SVG_USE_PORT` env var to
#     enable an experimental flowchart layout "port"; reading the environment is
#     non-deterministic over untrusted input, and the port mis-routes cyclic
#     back-edges (detached arrowheads). The default `layout::compute_layout`
#     path routes cycles correctly, so the port stays off. Because the port is
#     unreachable, `mermaid_port::compute_layout_ported` carries an
#     `#[allow(dead_code)]`; the module is kept verbatim (not deleted) so future
#     re-vendor diffs stay minimal.
#  4. Dropped the unused `petgraph` and `regex` dependencies (declared upstream,
#     referenced nowhere in the vendored source; `cargo shear` confirms).
#  5. `thiserror` pinned to "2" (upstream "1.0") to match the workspace; the
#     `#[derive(Error)]` / `#[error("…")]` API used in `src/error.rs` is
#     unchanged across the major.
#  6. `cargo fmt` (rustfmt) applied so the crate satisfies the workspace fmt
#     gate; no semantic change.
#  7. LOCAL REWRITE (src/sequence_diagram.rs; deliberately NOT marked in-source
#     — this note is the sole record, so re-apply it on every upstream
#     upgrade): the upstream sequence parser hard-failed ("Unrecognized
#     sequenceDiagram line") on most of the standard Mermaid sequence grammar. Added: `activate`/`deactivate`
#     (+ the `+`/`-` message shorthand) drawn as lifeline activation bars;
#     `actor`; `create`/`destroy`; `box … end`; `autonumber` (message-number
#     prefixes); `title`; `accTitle`/`accDescr` (incl. `{ … }` blocks) and
#     `links`/`link`/`properties` accepted-and-skipped; `par`/`and`,
#     `critical`/`option`, `break`, `rect` fragments; the full arrow set
#     (`->`, `-->`, `-x`, `--x`, `-)`, `--)`, `<<->>`, `<<-->>`) with per-type
#     markers. Keyword matching is now case-insensitive and word-bounded
#     (Mermaid's lexer is case-insensitive; `optimize…` is no longer an `opt`
#     fragment). Arrow markers are theme-colored (were unstyled black,
#     invisible-on-dark) and note text is fixed-dark on the fixed light-yellow
#     note fill. Covered by the (likewise unmarked) `test_sequence_*` tests in
#     src/lib.rs.
#  8. LOCAL MODIFICATION (new `unicode-width` dep): text width estimates count
#     East Asian wide characters as two narrow units via `text_wrap::
#     display_width_units` (upstream counted chars/graphemes, halving CJK label
#     widths so they overflowed their nodes). Touches `text_wrap.rs` and the
#     local estimators in `sequence_diagram.rs` / `xychart_diagram.rs` /
#     `mindmap_diagram.rs`; ASCII measurement is unchanged. Covered by the
#     `test_cjk_*` tests in src/lib.rs.
#  9. LOCAL MODIFICATION (src/parser.rs): support Mermaid's open edge-label
#     syntax (`A -- text --> B`, `-- text ---`, `== text ==>`, `== text ===`,
#     `-. text .-`; upstream only parsed the `|text|` form plus `-. text .->`),
#     and make `find_edge_start` bracket/quote-aware so edge tokens inside node
#     labels (`A["x --> y"]`) are not treated as edges. Upstream parsed
#     `B -- 是 --> C` as a literal node named "B -- 是". Covered by the
#     `test_open_edge_label_*` / `test_edge_tokens_inside_node_labels_*` tests
#     in src/lib.rs.
# 10. LOCAL MODIFICATION (src/text_wrap.rs): a single unbreakable token (a
#     "word" with no internal whitespace) is kept whole on its own line and the
#     box widens to fit it, instead of being hard-sliced mid-identifier at a
#     grapheme boundary once it exceeds `wrapping_width` (upstream sliced
#     `mark_filter_restore_context` into `mark_filter_restore_conte` + `xt`).
#     This matches Mermaid's default `htmlLabels: true` rendering, which this
#     port does not implement (src/config.rs), so it is MORE faithful to
#     upstream Mermaid. Because `wrap_text_lines` is the shared wrapper, this
#     applies to ALL of its callers — flowchart node labels, edge labels, and
#     subgraph titles, plus state-diagram node/edge labels (state diagrams parse
#     into the same `FlowchartGraph` and reuse this layout/renderer) — not just
#     node boxes. The class/er/requirement diagrams have their own renderers that
#     call only `line_width` (single-line, no wrapping), so they are unaffected.
#     Only a pathologically long token — wider than
#     SINGLE_TOKEN_WIDTH_CAP_FACTOR (5x) the wrap width — is force-broken,
#     preferring the last identifier boundary (`_`/`-`/`.`/`/`) under the cap.
#     Per-diagram width is now intentionally bounded only by the downstream
#     rasterizer's PNG caps (xai-grok-mermaid), not by the layout — a deliberate
#     legibility-vs-completeness tradeoff. Multi-word labels still wrap at spaces
#     as before (`wrapping_width` unchanged). Covered by the unit tests in
#     `src/text_wrap.rs`.
# 11. LOCAL MODIFICATION (src/layout.rs): flowchart edges whose endpoint is a
#     subgraph id (cluster-target edges) have the dagre route points that fall
#     strictly inside the destination/source cluster rect trimmed (via
#     `trim_cluster_interior_points`) before `clip_edge_to_boundaries`, so the
#     edge approaches the cluster boundary from outside instead of routing to the
#     first-declared interior member (`subgraph_entry_node_id`) and curling back.
#     A single transition point is kept per trimmed side; the polyline never
#     drops below two points. Only forward (non-back) cluster-target edges are
#     affected — node-target edges and back edges are unchanged. Covered by the
#     `trim_*` tests in src/layout.rs.
# 12. LOCAL REWRITE (src/xychart_diagram.rs): upstream only parsed a numeric
#     x-axis (`x-axis min --> max`) + a single `line`, hard-failing on the
#     categorical form `x-axis ["a", …]` (so such charts fell back to a code
#     block — "opening image for this diagram fails"). Added: categorical
#     (band-scale) x-axis; optional quoted axis titles (y rotated, x centered);
#     quote stripping for the title/labels; multiple `line` series in distinct
#     palette colors; y auto-ranging when no explicit range is given; and
#     theme-colored axes/text (was a fixed near-black, invisible on dark). `bar`
#     stays unsupported (ignored). Covered by `xychart_diagram::tests` here and
#     the `categorical_xychart_*` raster test in
#     crates/codegen/xai-grok-mermaid/tests/pure_engine.rs.
#
# Re-audit checklist:
#  - This crate's own source contains no `unsafe` and no filesystem / network I/O.
#    Text metrics are font-free (fixed char-width in `src/text_wrap.rs`), so the
#    engine performs NO system-font enumeration or on-disk font cache — glyph
#    rasterization is the separate, bundled-font `xai-grok-mermaid::rasterize`.
#  - SIBLING VENDORED LAYOUT DEPS (this header is the audit source-of-truth for
#    the whole stack): `ordered_hashmap` retains two `unsafe` raw-pointer blocks
#    in `iter_mut`/`values_mut` (documented + re-audited in its own Cargo.toml);
#    `dagre_rust` and `graphlib_rust` contain no `unsafe` (dagre's upstream
#    `static mut` counter was replaced with an `AtomicUsize` — see its Cargo.toml).
#  - YAML frontmatter parsing (`src/config.rs`, `src/kanban_diagram.rs`) uses the
#    workspace `serde_yaml`; it parses in-memory source only (no file/URL refs).
[package]
name = "mermaid-to-svg"
version = "0.1.0"
edition = "2021"
description = "Convert Mermaid diagram source to SVG via a dagre layout port (vendored, library-only)"
license = "MIT"
repository = "https://github.com/warpdotdev/mermaid-to-svg"
publish = false

[lib]
name = "mermaid_to_svg"
path = "src/lib.rs"
doctest = false

[dependencies]
thiserror = "2"
dagre_rust = { path = "../dagre_rust" }
graphlib_rust = { path = "../graphlib_rust" }
unicode-segmentation = "1"
unicode-width = "0.2"
serde_yaml = "0.9"

# Clippy lints local/path crates (this vendored crate is one) under the
# workspace's `-D warnings`. We do not restyle upstream third-party code, so
# allow clippy here; our own crate (xai-grok-mermaid) is still fully linted.
[lints.clippy]
all = { level = "allow", priority = -1 }
