zombie-mermaid 2.2.1 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -0
- package/README.md +7 -2
- package/dist/ascii.cjs +9 -9
- package/dist/ascii.cjs.map +1 -1
- package/dist/ascii.js +4069 -3969
- package/dist/ascii.js.map +1 -1
- package/dist/cli.js +7605 -7381
- package/dist/index.cjs +52 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +7613 -7459
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +14142 -13717
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +14142 -13717
- package/dist/mcp.js.map +1 -1
- package/package.json +27 -5
- package/packages/ascii-renderer/LICENSE +22 -0
- package/{src/ascii → packages/ascii-renderer/src}/class-diagram.ts +277 -57
- package/{src/ascii → packages/ascii-renderer/src}/er-diagram.ts +2 -2
- package/packages/ascii-renderer/src/flowchart.ts +94 -0
- package/{src/ascii → packages/ascii-renderer/src}/grid.ts +23 -0
- package/{src/ascii → packages/ascii-renderer/src}/index.ts +13 -84
- package/{src/ascii → packages/ascii-renderer/src}/registry.ts +23 -12
- package/{src/ascii → packages/ascii-renderer/src}/sequence.ts +55 -8
- package/{src/ascii → packages/ascii-renderer/src}/xychart.ts +6 -3
- package/packages/core/LICENSE +22 -0
- package/packages/core/src/click-directive.ts +106 -0
- package/packages/core/src/color-utils.ts +205 -0
- package/packages/core/src/diagram-type.ts +35 -0
- package/packages/core/src/direction-override.ts +46 -0
- package/packages/core/src/direction.ts +56 -0
- package/packages/core/src/index.ts +34 -0
- package/packages/core/src/init-directive.ts +248 -0
- package/packages/core/src/multiline-utils.ts +275 -0
- package/packages/core/src/statements.ts +197 -0
- package/packages/core/src/style-directives.ts +214 -0
- package/packages/core/src/text-metrics.ts +498 -0
- package/packages/core/src/theme.ts +696 -0
- package/packages/core/src/types.ts +670 -0
- package/packages/mcp/LICENSE +22 -0
- package/{src/mcp → packages/mcp/src}/server.ts +34 -2
- package/{src/mcp → packages/mcp/src}/tools/check-sequence-activations.ts +8 -5
- package/packages/mcp/src/tools/fix-sequence-activations.ts +77 -0
- package/{src/mcp → packages/mcp/src}/tools/render-ascii.ts +2 -2
- package/{src/mcp → packages/mcp/src}/tools/render-svg.ts +1 -1
- package/packages/mermaid-parser/LICENSE +22 -0
- package/{src → packages/mermaid-parser/src}/class/parser.ts +86 -8
- package/{src → packages/mermaid-parser/src}/er/parser.ts +59 -26
- package/packages/mermaid-parser/src/index.ts +48 -0
- package/{src → packages/mermaid-parser/src}/sequence/activation-check.ts +4 -3
- package/packages/mermaid-parser/src/sequence/activation-fix.ts +112 -0
- package/{src → packages/mermaid-parser/src}/sequence/parser.ts +74 -16
- package/{src → packages/mermaid-parser/src}/xychart/parser.ts +84 -6
- package/packages/svg-renderer/LICENSE +22 -0
- package/{src → packages/svg-renderer/src}/class/layout.ts +8 -4
- package/{src → packages/svg-renderer/src}/class/renderer.ts +7 -6
- package/packages/svg-renderer/src/edge-curves.ts +204 -0
- package/packages/svg-renderer/src/elk-instance.ts +292 -0
- package/{src → packages/svg-renderer/src}/er/layout.ts +6 -4
- package/{src → packages/svg-renderer/src}/er/renderer.ts +4 -4
- package/packages/svg-renderer/src/index.ts +58 -0
- package/packages/svg-renderer/src/layout-engine/constants.ts +19 -0
- package/packages/svg-renderer/src/layout-engine/edge-bundling.ts +379 -0
- package/packages/svg-renderer/src/layout-engine/elk-adapter-utils.ts +81 -0
- package/packages/svg-renderer/src/layout-engine/elk-graph-builder.ts +240 -0
- package/packages/svg-renderer/src/layout-engine/from-elk.ts +685 -0
- package/packages/svg-renderer/src/layout-engine/layer-alignment.ts +174 -0
- package/packages/svg-renderer/src/layout-engine/to-elk.ts +695 -0
- package/packages/svg-renderer/src/layout-engine.ts +74 -0
- package/packages/svg-renderer/src/layout.ts +8 -0
- package/packages/svg-renderer/src/renderer.ts +1485 -0
- package/packages/svg-renderer/src/resolve-colors.ts +339 -0
- package/{src → packages/svg-renderer/src}/sequence/layout.ts +2 -6
- package/{src → packages/svg-renderer/src}/sequence/renderer.ts +4 -4
- package/packages/svg-renderer/src/shape-clipping.ts +197 -0
- package/packages/svg-renderer/src/styles.ts +118 -0
- package/{src → packages/svg-renderer/src}/xychart/layout.ts +2 -2
- package/{src → packages/svg-renderer/src}/xychart/renderer.ts +6 -6
- package/src/__tests__/ascii-ansi.test.ts +6 -2
- package/src/__tests__/ascii-canvas-write.test.ts +2 -2
- package/src/__tests__/ascii-charset-border-junctions.test.ts +1 -1
- package/src/__tests__/ascii-cjk-width.test.ts +1 -1
- package/src/__tests__/ascii-class-box-occupancy.test.ts +147 -45
- package/src/__tests__/ascii-class-column-width-488-489.test.ts +1 -1
- package/src/__tests__/ascii-class-cross-level-jog-corruption.test.ts +187 -0
- package/src/__tests__/ascii-class-detour-label-routing-487.test.ts +1 -1
- package/src/__tests__/ascii-class-diagram-compartments.test.ts +1 -1
- package/src/__tests__/ascii-class-label-box-collision.test.ts +1 -1
- package/src/__tests__/ascii-class-label-row-collision-531.test.ts +1 -1
- package/src/__tests__/ascii-class-label-territory-row-awareness.test.ts +1 -1
- package/src/__tests__/ascii-class-padding.test.ts +1 -1
- package/src/__tests__/ascii-class-reciprocal-relationships-448.test.ts +86 -1
- package/src/__tests__/ascii-combining-mark-width.test.ts +2 -2
- package/src/__tests__/ascii-coords-overlay.test.ts +2 -2
- package/src/__tests__/ascii-decision-lr-box-start.test.ts +2 -2
- package/src/__tests__/ascii-display-width-unit.test.ts +1 -1
- package/src/__tests__/ascii-draw-arrows-coverage.test.ts +1 -1
- package/src/__tests__/ascii-draw-arrows-single-point-path.test.ts +12 -5
- package/src/__tests__/ascii-draw-bundles.test.ts +5 -5
- package/src/__tests__/ascii-edge-bundling-rank-violation-454.test.ts +1 -1
- package/src/__tests__/ascii-edge-bundling-routing.test.ts +9 -5
- package/src/__tests__/ascii-edge-cross-style-overlap.test.ts +10 -6
- package/src/__tests__/ascii-edge-ending-glyphs.test.ts +1 -1
- package/src/__tests__/ascii-edge-label-diagonal-fallback-418.test.ts +2 -2
- package/src/__tests__/ascii-edge-routing-fixes.test.ts +1 -1
- package/src/__tests__/ascii-edge-routing-single-point-path.test.ts +8 -4
- package/src/__tests__/ascii-edge-styles.test.ts +1 -1
- package/src/__tests__/ascii-emoji-cluster-width.test.ts +2 -2
- package/src/__tests__/ascii-er-box-occupancy.test.ts +1 -1
- package/src/__tests__/ascii-er-cardinality.test.ts +1 -1
- package/src/__tests__/ascii-er-corner-glyphs.test.ts +1 -1
- package/src/__tests__/ascii-er-jog-stray-line.test.ts +1 -1
- package/src/__tests__/ascii-er-label-padding.test.ts +1 -1
- package/src/__tests__/ascii-er-padding.test.ts +1 -1
- package/src/__tests__/ascii-er-relationship-label-corruption-350.test.ts +1 -1
- package/src/__tests__/ascii-er-relationship-overwrite.test.ts +1 -1
- package/src/__tests__/ascii-er-stray-connectors.test.ts +7 -4
- package/src/__tests__/ascii-er-unrelated-stem-separation-411.test.ts +1 -1
- package/src/__tests__/ascii-er-vertical-one-marker.test.ts +1 -1
- package/src/__tests__/ascii-grid-deep-chain.test.ts +4 -4
- package/src/__tests__/ascii-hyperlinks.test.ts +9 -6
- package/src/__tests__/ascii-label-line-terminal-fallback.test.ts +8 -4
- package/src/__tests__/ascii-lane-search.test.ts +1 -1
- package/src/__tests__/ascii-multibox-cjk-width.test.ts +1 -1
- package/src/__tests__/ascii-multiline.test.ts +6 -3
- package/src/__tests__/ascii-nested-subgraph-sibling-order-444.test.ts +8 -5
- package/src/__tests__/ascii-package-boundary.test.ts +47 -37
- package/src/__tests__/ascii-padding-edge-cases.test.ts +1 -1
- package/src/__tests__/ascii-parallel-edges-329.test.ts +8 -5
- package/src/__tests__/ascii-pathfinder-route-edge.test.ts +14 -4
- package/src/__tests__/ascii-reverse-direction-edges-629.test.ts +9 -5
- package/src/__tests__/ascii-sequence-alt-else-label.test.ts +1 -1
- package/src/__tests__/ascii-sequence-block-wall-clearance.test.ts +1 -1
- package/src/__tests__/ascii-sequence-box-group.test.ts +1 -1
- package/src/__tests__/ascii-sequence-cjk-width.test.ts +1 -1
- package/src/__tests__/ascii-sequence-create-destroy.test.ts +1 -1
- package/src/__tests__/ascii-sequence-form-invariants.test.ts +48 -50
- package/src/__tests__/ascii-sequence-mermaid-parity.test.ts +1 -1
- package/src/__tests__/ascii-sequence-notes.test.ts +1 -1
- package/src/__tests__/ascii-sequence-padding.test.ts +1 -1
- package/src/__tests__/ascii-sequence-self-arrow.test.ts +1 -1
- package/src/__tests__/ascii-shape-diamond.test.ts +3 -3
- package/src/__tests__/ascii-shape-rectangle.test.ts +5 -5
- package/src/__tests__/ascii-shape-rounded.test.ts +3 -3
- package/src/__tests__/ascii-shapes-circle.test.ts +3 -3
- package/src/__tests__/ascii-shapes-hexagon.test.ts +3 -3
- package/src/__tests__/ascii-shapes-special.test.ts +10 -5
- package/src/__tests__/ascii-shapes-stadium.test.ts +3 -3
- package/src/__tests__/ascii-shapes-state.test.ts +15 -5
- package/src/__tests__/ascii-state-bidirectional-label-swap-530.test.ts +1 -1
- package/src/__tests__/ascii-subgraph-bbox.test.ts +8 -4
- package/src/__tests__/ascii-subgraph-direction-honored-445.test.ts +1 -1
- package/src/__tests__/ascii-subgraph-label-border-clip.test.ts +88 -25
- package/src/__tests__/ascii-subgraph-later-edgeless-301.test.ts +8 -4
- package/src/__tests__/ascii-subgraph-title-padding.test.ts +1 -1
- package/src/__tests__/ascii-territory-unit.test.ts +2 -2
- package/src/__tests__/ascii-validate.test.ts +1 -1
- package/src/__tests__/ascii.test.ts +5 -2
- package/src/__tests__/box-color.test.ts +1 -1
- package/src/__tests__/class-arrow-directions.test.ts +1 -1
- package/src/__tests__/class-click-interactions.test.ts +3 -6
- package/src/__tests__/class-integration.test.ts +1 -1
- package/src/__tests__/class-notes.test.ts +3 -3
- package/src/__tests__/class-parser-error-messages.test.ts +162 -0
- package/src/__tests__/class-parser.test.ts +6 -6
- package/src/__tests__/class-styling.test.ts +2 -2
- package/src/__tests__/cli-render.test.ts +16 -1
- package/src/__tests__/direction-override.test.ts +1 -1
- package/src/__tests__/draw-lines.test.ts +2 -2
- package/src/__tests__/edge-cell-styles.test.ts +5 -2
- package/src/__tests__/elk-layout-cache.test.ts +6 -4
- package/src/__tests__/er-click-unsupported.test.ts +5 -8
- package/src/__tests__/er-parser-error-messages.test.ts +82 -0
- package/src/__tests__/er-parser.test.ts +3 -6
- package/src/__tests__/expanded-shapes.test.ts +1 -1
- package/src/__tests__/grid-occupancy.test.ts +1 -1
- package/src/__tests__/mcp-check-sequence-activations-tool.test.ts +1 -1
- package/src/__tests__/mcp-fix-sequence-activations-tool.test.ts +134 -0
- package/src/__tests__/mcp-render-ascii-tool.test.ts +5 -4
- package/src/__tests__/mcp-render-svg-theme-guard.test.ts +3 -3
- package/src/__tests__/mcp-render-svg-tool.test.ts +1 -1
- package/src/__tests__/mcp-server.test.ts +30 -1
- package/src/__tests__/multiline-labels.test.ts +29 -18
- package/src/__tests__/parser.test.ts +117 -5
- package/src/__tests__/pathfinder.test.ts +11 -4
- package/src/__tests__/render-options-overrides.test.ts +28 -21
- package/src/__tests__/render-options-per-type.test.ts +13 -9
- package/src/__tests__/resolve-colors.test.ts +1 -1
- package/src/__tests__/self-loop-edges.test.ts +112 -0
- package/src/__tests__/sequence-activation-check.test.ts +7 -8
- package/src/__tests__/sequence-activation-fix.test.ts +91 -0
- package/src/__tests__/sequence-layout.test.ts +4 -7
- package/src/__tests__/sequence-parser-syntax-errors.test.ts +179 -0
- package/src/__tests__/sequence-parser.test.ts +3 -6
- package/src/__tests__/statements.test.ts +53 -35
- package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +21 -21
- package/src/__tests__/theme-palette-contrast.test.ts +84 -0
- package/src/__tests__/workspace-package-boundaries.test.ts +199 -25
- package/src/__tests__/xychart-ascii.test.ts +1 -1
- package/src/__tests__/xychart-colors.test.ts +3 -2
- package/src/__tests__/xychart-layout.test.ts +1 -1
- package/src/__tests__/xychart-parser-errors.test.ts +95 -0
- package/src/browser.ts +8 -2
- package/src/cli/mcp.ts +1 -1
- package/src/cli/render.ts +59 -25
- package/src/cli/web.ts +1 -1
- package/src/diagram-registry.ts +190 -25
- package/src/index.ts +34 -131
- package/src/parser.ts +102 -40
- /package/{src/ascii → packages/ascii-renderer/src}/ansi.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/canvas.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/converter.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/coords.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/display-width.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw-arrows.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw-boxes.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw-bundles.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw-lines.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw-subgraphs.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/draw.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/edge-bundling.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/edge-cell-styles.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/edge-routing.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/grid-occupancy.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/hyperlinks.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/lane-search.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/multiline-utils.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/pathfinder.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/circle.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/corners.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/diamond.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/hexagon.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/index.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/rectangle.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/rounded.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/special.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/stadium.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/state.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/shapes/types.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/territory.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/types.ts +0 -0
- /package/{src/ascii → packages/ascii-renderer/src}/validate.ts +0 -0
- /package/{src/mcp → packages/mcp/src}/index.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/class/format.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/class/types.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/er/types.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/expanded-shapes.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/sequence/box-color.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/sequence/types.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/xychart/colors.ts +0 -0
- /package/{src → packages/mermaid-parser/src}/xychart/types.ts +0 -0
|
@@ -8,9 +8,9 @@ import type {
|
|
|
8
8
|
GridLine,
|
|
9
9
|
PlotArea,
|
|
10
10
|
LegendItem,
|
|
11
|
-
} from '
|
|
11
|
+
} from '@zombie-mermaid/mermaid-parser'
|
|
12
12
|
import type { XyChartRenderOptions } from '@zombie-mermaid/core'
|
|
13
|
-
import { estimateTextWidth } from '
|
|
13
|
+
import { estimateTextWidth } from '../styles.ts'
|
|
14
14
|
|
|
15
15
|
// ============================================================================
|
|
16
16
|
// XY Chart layout engine
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { PositionedXYChart } from '
|
|
1
|
+
import type { PositionedXYChart } from '@zombie-mermaid/mermaid-parser'
|
|
2
2
|
import type { DiagramColors, SvgEmitOptions } from '@zombie-mermaid/core'
|
|
3
3
|
import { svgOpenTag, buildStyleBlock, styleOpenTag } from '@zombie-mermaid/core'
|
|
4
|
+
import { withDataSrc } from '../renderer.ts'
|
|
5
|
+
import { TEXT_BASELINE_SHIFT, estimateTextWidth } from '../styles.ts'
|
|
4
6
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from '@zombie-mermaid/svg-renderer'
|
|
9
|
-
import { getSeriesColor, CHART_ACCENT_FALLBACK } from './colors.ts'
|
|
7
|
+
getSeriesColor,
|
|
8
|
+
CHART_ACCENT_FALLBACK,
|
|
9
|
+
} from '@zombie-mermaid/mermaid-parser'
|
|
10
10
|
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// XY Chart SVG renderer
|
|
@@ -11,8 +11,12 @@ import {
|
|
|
11
11
|
colorizeChar,
|
|
12
12
|
colorizeLine,
|
|
13
13
|
colorizeText,
|
|
14
|
-
} from '
|
|
15
|
-
import type {
|
|
14
|
+
} from '../../packages/ascii-renderer/src/ansi.ts'
|
|
15
|
+
import type {
|
|
16
|
+
CharRole,
|
|
17
|
+
AsciiTheme,
|
|
18
|
+
ColorMode,
|
|
19
|
+
} from '../../packages/ascii-renderer/src/types.ts'
|
|
16
20
|
import type { DiagramColors } from '@zombie-mermaid/core'
|
|
17
21
|
|
|
18
22
|
const RESET = '\x1b[0m'
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
mkRoleCanvas,
|
|
18
18
|
write,
|
|
19
19
|
getCanvasSize,
|
|
20
|
-
} from '
|
|
21
|
-
import type { CharRole } from '
|
|
20
|
+
} from '../../packages/ascii-renderer/src/canvas.ts'
|
|
21
|
+
import type { CharRole } from '../../packages/ascii-renderer/src/types.ts'
|
|
22
22
|
|
|
23
23
|
describe('canvas.ts write()', () => {
|
|
24
24
|
it('writes within bounds, including exactly on the inclusive max edge', () => {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* the ASCII equivalent ('+').
|
|
10
10
|
*/
|
|
11
11
|
import { describe, it, expect } from 'vitest'
|
|
12
|
-
import { renderMermaidASCII } from '
|
|
12
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
13
13
|
|
|
14
14
|
describe('ASCII vs Unicode charset: box-start border junctions', () => {
|
|
15
15
|
it('draws a "+" junction on a plain top-down edge, matching the Unicode T-junction', () => {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* just that the fix's own helper agrees with itself.
|
|
15
15
|
*/
|
|
16
16
|
import { describe, it, expect } from 'vitest'
|
|
17
|
-
import { renderMermaidASCII } from '
|
|
17
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
18
18
|
import {
|
|
19
19
|
terminalDisplayWidth,
|
|
20
20
|
assertUniformDisplayWidth,
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// ASCII class diagram box-occupancy invariants
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
// `setCGuarded`/`boxCells`/`regionClear` — fixing issue #350
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// relationship line/label ever land on top of
|
|
10
|
-
// question issue #350 asked for ER diagrams,
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
4
|
+
// packages/ascii-renderer/src/er-diagram.ts has an occupancy guard —
|
|
5
|
+
// `setCGuarded`/`boxCells`/`regionClear` — fixing issue #350.
|
|
6
|
+
// packages/ascii-renderer/src/class-diagram.ts now generalizes that same
|
|
7
|
+
// guard (see its own `boxCells`/`setCGuarded`, plus an obstruction-aware
|
|
8
|
+
// same-level detour row) to close issue #953's class-diagram cases. This
|
|
9
|
+
// suite sweeps the same "does a relationship line/label ever land on top of
|
|
10
|
+
// an unrelated class's box" question issue #350 asked for ER diagrams,
|
|
11
|
+
// generalized to class diagrams. Two cases below (the same-level detour
|
|
12
|
+
// crossing a taller, in-between class's box) used to be confirmed-broken and
|
|
13
|
+
// marked `it.fails`; they're now plain `it()` cases, verifying the fix.
|
|
14
14
|
// ============================================================================
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from 'vitest'
|
|
17
|
-
import { renderMermaidASCII } from '
|
|
17
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
18
18
|
import { findBoxRect, rectsOverlap } from './helpers/ascii-form.ts'
|
|
19
19
|
|
|
20
20
|
function expectNoBoxOverlap(ascii: string, names: string[]): void {
|
|
@@ -101,18 +101,15 @@ describe('ASCII class diagrams — class boxes never overlap', () => {
|
|
|
101
101
|
expectNoBoxOverlap(ascii, ['Alpha', 'Mid', 'Charlie'])
|
|
102
102
|
})
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
'3-node cycle, Mid (middle) has 6 attributes: detour line corrupts an attribute row',
|
|
114
|
-
() => {
|
|
115
|
-
const src = `classDiagram
|
|
104
|
+
// The same-level branch's detour row used to be computed only from the
|
|
105
|
+
// relationship's own two endpoints (Alpha, Charlie), never checking
|
|
106
|
+
// whether Mid — sitting between them in the same row — was taller and
|
|
107
|
+
// extended below that row. class-diagram.ts now searches for such a
|
|
108
|
+
// same-row obstruction and routes the detour below its bottom edge too
|
|
109
|
+
// (generalizing er-diagram.ts's obstructionBottom guard, issue #350),
|
|
110
|
+
// so the detour's horizontal segment no longer cuts through Mid's box.
|
|
111
|
+
it('3-node cycle, Mid (middle) has 6 attributes: detour line corrupts an attribute row', () => {
|
|
112
|
+
const src = `classDiagram
|
|
116
113
|
class Alpha
|
|
117
114
|
class Mid {
|
|
118
115
|
${manyAttrs('b', 6)}
|
|
@@ -121,7 +118,79 @@ ${manyAttrs('b', 6)}
|
|
|
121
118
|
Alpha --> Mid
|
|
122
119
|
Mid --> Charlie
|
|
123
120
|
Charlie --> Alpha`
|
|
124
|
-
|
|
121
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
122
|
+
expectAllPresentOnce(ascii, [
|
|
123
|
+
'+ b0: String',
|
|
124
|
+
'+ b1: String',
|
|
125
|
+
'+ b2: String',
|
|
126
|
+
'+ b3: String',
|
|
127
|
+
'+ b4: String',
|
|
128
|
+
'+ b5: String',
|
|
129
|
+
])
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// The same-row obstruction search (see the test above) must skip a class
|
|
133
|
+
// on a *different* level/row, even when that class's box geometrically
|
|
134
|
+
// overlaps the detour's horizontal span — not just when it happens to sit
|
|
135
|
+
// off to the side where the search would ignore it anyway regardless of
|
|
136
|
+
// the `other.y !== fromP.y` filter. `Root`/`Kid` are a real root/child
|
|
137
|
+
// pair via the level-BFS (Root has no parent, Kid is its level-1 child),
|
|
138
|
+
// placed on a different row from the Alpha/Mid/Charlie cycle.
|
|
139
|
+
//
|
|
140
|
+
// Two orderings of the same Root/Kid pair are compared: declaring Root
|
|
141
|
+
// first places Kid's column off to the side, outside the Alpha-to-Charlie
|
|
142
|
+
// detour span; declaring Root between Alpha and Mid places Kid's column
|
|
143
|
+
// so it overlaps Alpha's own range instead (confirmed below via
|
|
144
|
+
// `findBoxRect`). If the different-row filter worked, both orderings
|
|
145
|
+
// render the cycle identically — Root/Kid's actual row is irrelevant to
|
|
146
|
+
// it either way. A test that only used the non-overlapping ordering would
|
|
147
|
+
// pass even with the filter deleted (verified: an earlier version of this
|
|
148
|
+
// test did exactly that, and CodeRabbit correctly flagged it as not
|
|
149
|
+
// actually exercising the filter — see the PR discussion). Sabotage-
|
|
150
|
+
// verified: deleting the filter leaves both orderings' `+ bN: String`
|
|
151
|
+
// lines intact but makes the overlapping ordering one row taller than the
|
|
152
|
+
// non-overlapping one (19 vs. 18), which the equality assertion below
|
|
153
|
+
// catches.
|
|
154
|
+
it('3-node cycle, unrelated Root->Kid pair on a different level: obstruction search ignores it regardless of whether it overlaps the detour span', () => {
|
|
155
|
+
function withRootKid(rootDeclaredBetweenAlphaAndMid: boolean): string {
|
|
156
|
+
const rootAndKid = ` class Root
|
|
157
|
+
class Kid
|
|
158
|
+
`
|
|
159
|
+
return `classDiagram
|
|
160
|
+
${rootDeclaredBetweenAlphaAndMid ? '' : rootAndKid} class Alpha
|
|
161
|
+
${rootDeclaredBetweenAlphaAndMid ? rootAndKid : ''} class Mid {
|
|
162
|
+
${manyAttrs('b', 6)}
|
|
163
|
+
}
|
|
164
|
+
class Charlie
|
|
165
|
+
Alpha --> Mid
|
|
166
|
+
Mid --> Charlie
|
|
167
|
+
Charlie --> Alpha
|
|
168
|
+
Root --> Kid`
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const nonOverlapping = renderMermaidASCII(withRootKid(false), {
|
|
172
|
+
useAscii: true,
|
|
173
|
+
})
|
|
174
|
+
const overlapping = renderMermaidASCII(withRootKid(true), {
|
|
175
|
+
useAscii: true,
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// Confirms the geometry this test relies on: in the "overlapping"
|
|
179
|
+
// ordering, Kid really does sit on a different row from the cycle, and
|
|
180
|
+
// really does overlap Alpha's own column range (i.e. the obstruction
|
|
181
|
+
// search has something to incorrectly notice if the different-row
|
|
182
|
+
// filter is missing); in the "non-overlapping" ordering, it doesn't.
|
|
183
|
+
const overlappingAlphaRect = findBoxRect(overlapping, 'Alpha')
|
|
184
|
+
const overlappingKidRect = findBoxRect(overlapping, 'Kid')
|
|
185
|
+
expect(overlappingKidRect.y0).toBeGreaterThan(overlappingAlphaRect.y1)
|
|
186
|
+
expect(overlappingKidRect.x0).toBeLessThan(overlappingAlphaRect.x1)
|
|
187
|
+
const nonOverlappingAlphaRect = findBoxRect(nonOverlapping, 'Alpha')
|
|
188
|
+
const nonOverlappingKidRect = findBoxRect(nonOverlapping, 'Kid')
|
|
189
|
+
expect(nonOverlappingKidRect.x1).toBeLessThanOrEqual(
|
|
190
|
+
nonOverlappingAlphaRect.x0,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
for (const ascii of [nonOverlapping, overlapping]) {
|
|
125
194
|
expectAllPresentOnce(ascii, [
|
|
126
195
|
'+ b0: String',
|
|
127
196
|
'+ b1: String',
|
|
@@ -130,8 +199,43 @@ ${manyAttrs('b', 6)}
|
|
|
130
199
|
'+ b4: String',
|
|
131
200
|
'+ b5: String',
|
|
132
201
|
])
|
|
133
|
-
|
|
134
|
-
|
|
202
|
+
expectNoBoxOverlap(ascii, ['Alpha', 'Mid', 'Charlie', 'Root', 'Kid'])
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// The real check: Kid overlapping the detour span must not change the
|
|
206
|
+
// cycle's own rendered height compared to Kid sitting clear of it.
|
|
207
|
+
expect(overlapping.split('\n').length).toBe(
|
|
208
|
+
nonOverlapping.split('\n').length,
|
|
209
|
+
)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// `computeLabelAnchor`'s same-level branch used to recompute the label's
|
|
213
|
+
// row from scratch (`Math.max(fromBY, toBY) + 2`) instead of reusing the
|
|
214
|
+
// connector's own obstruction-aware `detourY` (`sameLevelDetourY` above)
|
|
215
|
+
// — so a *labeled* same-level relationship still landed its label inside
|
|
216
|
+
// Mid's box even after the unlabeled connector-line fix above, the same
|
|
217
|
+
// corruption in a sibling code path (caught in review on PR #957).
|
|
218
|
+
it('3-node cycle, Mid (middle) has 6 attributes, labeled wrap-around relationship: label no longer corrupts an attribute row', () => {
|
|
219
|
+
const src = `classDiagram
|
|
220
|
+
class Alpha
|
|
221
|
+
class Mid {
|
|
222
|
+
${manyAttrs('b', 6)}
|
|
223
|
+
}
|
|
224
|
+
class Charlie
|
|
225
|
+
Alpha --> Mid
|
|
226
|
+
Mid --> Charlie
|
|
227
|
+
Charlie --> Alpha : a rather long descriptive label`
|
|
228
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
229
|
+
expectAllPresentOnce(ascii, [
|
|
230
|
+
'+ b0: String',
|
|
231
|
+
'+ b1: String',
|
|
232
|
+
'+ b2: String',
|
|
233
|
+
'+ b3: String',
|
|
234
|
+
'+ b4: String',
|
|
235
|
+
'+ b5: String',
|
|
236
|
+
])
|
|
237
|
+
expect(ascii).toContain('a rather long descriptive label')
|
|
238
|
+
})
|
|
135
239
|
|
|
136
240
|
it('3-node cycle, long relationship label, no tall obstruction', () => {
|
|
137
241
|
const src = `classDiagram
|
|
@@ -176,14 +280,13 @@ ${manyAttrs('c', 6)}
|
|
|
176
280
|
expectNoBoxOverlap(ascii, ['A', 'B', 'C', 'D'])
|
|
177
281
|
})
|
|
178
282
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const src = `classDiagram
|
|
283
|
+
// A 4-node cycle (A->B->C->D->A) plus a skip edge (A->C) also fell into
|
|
284
|
+
// the same unguarded same-level detour as the 3-node case above — a
|
|
285
|
+
// second, independently-verified topology hitting the same code gap,
|
|
286
|
+
// this time skipping over B's box. Fixed by the same obstruction-aware
|
|
287
|
+
// detour routing (see the 3-node cycle test above).
|
|
288
|
+
it('4-node cycle with a skip edge, tall middle class: detour corrupts an attribute row', () => {
|
|
289
|
+
const src = `classDiagram
|
|
187
290
|
class A
|
|
188
291
|
class B {
|
|
189
292
|
${manyAttrs('b', 6)}
|
|
@@ -195,17 +298,16 @@ ${manyAttrs('b', 6)}
|
|
|
195
298
|
C --> D
|
|
196
299
|
D --> A
|
|
197
300
|
A --> C`
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
301
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
302
|
+
expectAllPresentOnce(ascii, [
|
|
303
|
+
'+ b0: String',
|
|
304
|
+
'+ b1: String',
|
|
305
|
+
'+ b2: String',
|
|
306
|
+
'+ b3: String',
|
|
307
|
+
'+ b4: String',
|
|
308
|
+
'+ b5: String',
|
|
309
|
+
])
|
|
310
|
+
})
|
|
209
311
|
|
|
210
312
|
it('3 siblings + 2 children, crossing inheritance edges', () => {
|
|
211
313
|
const src = `classDiagram
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { describe, it, expect } from 'vitest'
|
|
24
|
-
import { renderMermaidASCII } from '
|
|
24
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
25
25
|
import { assertUniformDisplayWidth } from './helpers/terminal-display-width.ts'
|
|
26
26
|
|
|
27
27
|
/** Same source as the "Class: All 6 Relationship Types" sample (samples-data.ts). */
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// ASCII class diagram — cross-level connector jog corrupting an intervening
|
|
3
|
+
// box's text
|
|
4
|
+
//
|
|
5
|
+
// Discovered incidentally while writing ascii-class-box-occupancy.test.ts's
|
|
6
|
+
// coverage for issue #953/PR #957 (the *same-level* relationship cycle's
|
|
7
|
+
// detour line lacking an occupancy guard). This is a distinct bug in a
|
|
8
|
+
// different branch of src/ascii/class-diagram.ts's relationship-drawing
|
|
9
|
+
// pass — the "target is below source" (and, by the same missing guard,
|
|
10
|
+
// "target is above source") branch, used whenever a relationship's two
|
|
11
|
+
// classes land on different levels.
|
|
12
|
+
//
|
|
13
|
+
// That branch's "no collision" routing draws a straight horizontal jog
|
|
14
|
+
// connecting the source's lane column to the target's lane column at some
|
|
15
|
+
// row between them. The *only* check that decided this was safe to draw
|
|
16
|
+
// without a detour (`findClearColumn`) tests whether the source's own lane
|
|
17
|
+
// column is itself clear of boxes across the full row range — it says
|
|
18
|
+
// nothing about whether the horizontal jog's row is clear all the way over
|
|
19
|
+
// to the target's column. When a class ends up positioned far from its
|
|
20
|
+
// actual parent's column — e.g. a level's only child is always placed at
|
|
21
|
+
// the leftmost slot regardless of which sibling at the level above is its
|
|
22
|
+
// parent — and a *different*, taller same-level sibling's box sits between
|
|
23
|
+
// those two columns, the jog cuts straight through that sibling's box,
|
|
24
|
+
// silently replacing whichever attribute/method row it crosses.
|
|
25
|
+
//
|
|
26
|
+
// Fixed by giving src/ascii/class-diagram.ts the same kind of box-occupancy
|
|
27
|
+
// guard (`boxCells`/`setCGuarded`) src/ascii/er-diagram.ts already has for
|
|
28
|
+
// issue #350, scoped to the cross-level branches only — the same-level
|
|
29
|
+
// branch's own detour (PR #957's scope) is untouched here.
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
import { describe, it, expect } from 'vitest'
|
|
33
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
34
|
+
import { findBoxRect, rectsOverlap } from './helpers/ascii-form.ts'
|
|
35
|
+
|
|
36
|
+
function expectNoBoxOverlap(ascii: string, names: string[]): void {
|
|
37
|
+
const rects = names.map((n) => ({ n, r: findBoxRect(ascii, n) }))
|
|
38
|
+
for (let i = 0; i < rects.length; i++) {
|
|
39
|
+
for (let j = i + 1; j < rects.length; j++) {
|
|
40
|
+
expect(
|
|
41
|
+
rectsOverlap(rects[i]!.r, rects[j]!.r),
|
|
42
|
+
`${rects[i]!.n} and ${rects[j]!.n} boxes overlap`,
|
|
43
|
+
).toBe(false)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function manyAttrs(prefix: string, count: number): string {
|
|
49
|
+
return Array.from(
|
|
50
|
+
{ length: count },
|
|
51
|
+
(_, i) => ` +String ${prefix}${i}`,
|
|
52
|
+
).join('\n')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Assert every one of `needles` appears verbatim, exactly once, in `text`. */
|
|
56
|
+
function expectAllPresentOnce(text: string, needles: string[]): void {
|
|
57
|
+
for (const needle of needles) {
|
|
58
|
+
const count = text.split(needle).length - 1
|
|
59
|
+
expect(count, `expected "${needle}" to appear exactly once`).toBe(1)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe('ASCII class diagrams — cross-level connector jog never corrupts a box', () => {
|
|
64
|
+
it('root-level sibling sits between a source and its far-off, sole child (minimal repro)', () => {
|
|
65
|
+
// Left/TallMid/RightSrc are three unrelated level-0 roots (no cycle
|
|
66
|
+
// involved, unlike the original report — isolates this bug from the
|
|
67
|
+
// separately-tracked same-level detour issue). Kid is RightSrc's only
|
|
68
|
+
// child, so it lands at the leftmost slot of level 1 regardless of
|
|
69
|
+
// RightSrc's own (rightmost) column — the "no collision" routing then
|
|
70
|
+
// has to jog the whole width of the canvas, straight through TallMid.
|
|
71
|
+
const src = `classDiagram
|
|
72
|
+
class Left
|
|
73
|
+
class TallMid {
|
|
74
|
+
${manyAttrs('b', 6)}
|
|
75
|
+
}
|
|
76
|
+
class RightSrc
|
|
77
|
+
class Kid
|
|
78
|
+
RightSrc --> Kid`
|
|
79
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
80
|
+
expectAllPresentOnce(ascii, [
|
|
81
|
+
'+ b0: String',
|
|
82
|
+
'+ b1: String',
|
|
83
|
+
'+ b2: String',
|
|
84
|
+
'+ b3: String',
|
|
85
|
+
'+ b4: String',
|
|
86
|
+
'+ b5: String',
|
|
87
|
+
])
|
|
88
|
+
expectNoBoxOverlap(ascii, ['Left', 'TallMid', 'RightSrc', 'Kid'])
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('originally-reported repro: same-level cycle plus an unrelated root/child pair', () => {
|
|
92
|
+
// The exact topology this bug was first reported against. Alpha/Mid/
|
|
93
|
+
// Charlie form a same-level relationship cycle (falls to level 0 via
|
|
94
|
+
// the level-BFS's "no root" fallback); Root is a genuine level-0 root
|
|
95
|
+
// (declared after the cycle) with its own child Kid at level 1. Only
|
|
96
|
+
// "+ b4: String" is asserted here — the cross-level bug this file
|
|
97
|
+
// covers. "+ b1: String" is a *separate*, already-tracked corruption
|
|
98
|
+
// (the same-level cycle's own detour, issue #953/PR #957) and is
|
|
99
|
+
// deliberately not asserted on so this suite stays independent of
|
|
100
|
+
// that fix landing.
|
|
101
|
+
const src = `classDiagram
|
|
102
|
+
class Alpha
|
|
103
|
+
class Mid {
|
|
104
|
+
${manyAttrs('b', 6)}
|
|
105
|
+
}
|
|
106
|
+
class Charlie
|
|
107
|
+
class Root
|
|
108
|
+
class Kid
|
|
109
|
+
Alpha --> Mid
|
|
110
|
+
Mid --> Charlie
|
|
111
|
+
Charlie --> Alpha
|
|
112
|
+
Root --> Kid`
|
|
113
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
114
|
+
expect(
|
|
115
|
+
ascii,
|
|
116
|
+
'"+ b4: String" was overwritten by Root->Kid\'s jog',
|
|
117
|
+
).toContain('+ b4: String')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('deeper tree: a tall level-0 sibling between a level-1 source and its level-2 grandchild', () => {
|
|
121
|
+
const src = `classDiagram
|
|
122
|
+
class A
|
|
123
|
+
class TallMid {
|
|
124
|
+
${manyAttrs('b', 6)}
|
|
125
|
+
}
|
|
126
|
+
class B
|
|
127
|
+
class Kid1
|
|
128
|
+
class GrandKid
|
|
129
|
+
B --> Kid1
|
|
130
|
+
Kid1 --> GrandKid`
|
|
131
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
132
|
+
expectAllPresentOnce(ascii, [
|
|
133
|
+
'+ b0: String',
|
|
134
|
+
'+ b1: String',
|
|
135
|
+
'+ b2: String',
|
|
136
|
+
'+ b3: String',
|
|
137
|
+
'+ b4: String',
|
|
138
|
+
'+ b5: String',
|
|
139
|
+
])
|
|
140
|
+
expectNoBoxOverlap(ascii, ['A', 'TallMid', 'B', 'Kid1', 'GrandKid'])
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('more siblings: several unrelated roots plus a separate parent/child pair, inheritance marker', () => {
|
|
144
|
+
const src = `classDiagram
|
|
145
|
+
class Left
|
|
146
|
+
class TallMid {
|
|
147
|
+
${manyAttrs('d', 6)}
|
|
148
|
+
}
|
|
149
|
+
class RightSrc
|
|
150
|
+
class Kid
|
|
151
|
+
RightSrc <|-- Kid`
|
|
152
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
153
|
+
expectAllPresentOnce(ascii, [
|
|
154
|
+
'+ d0: String',
|
|
155
|
+
'+ d1: String',
|
|
156
|
+
'+ d2: String',
|
|
157
|
+
'+ d3: String',
|
|
158
|
+
'+ d4: String',
|
|
159
|
+
'+ d5: String',
|
|
160
|
+
])
|
|
161
|
+
expectNoBoxOverlap(ascii, ['Left', 'TallMid', 'RightSrc', 'Kid'])
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('"target above source" branch with a from-side marker renders without corrupting a box', () => {
|
|
165
|
+
// The "above" branch (this file's second `else if`) has no
|
|
166
|
+
// findClearColumn collision-avoidance at all — it always draws the
|
|
167
|
+
// straight jog/vertical/horizontal/vertical/jog path, so it's just as
|
|
168
|
+
// exposed to this bug as the "below" branch, and is guarded the same
|
|
169
|
+
// way here. A `Root --> A` / `A <|-- B` / `B --> A` back-edge forces
|
|
170
|
+
// A's level above B's (the level-assignment BFS keeps the *longest*
|
|
171
|
+
// path to a node, so B->A's back edge pushes A past B) — the
|
|
172
|
+
// `A <|-- B` edge then runs from the now-deeper A up to the
|
|
173
|
+
// shallower B, taking the "above" branch with its hollow-triangle
|
|
174
|
+
// marker at the 'from' end (A), a combination no other test in this
|
|
175
|
+
// file exercises.
|
|
176
|
+
const src = `classDiagram
|
|
177
|
+
class Root
|
|
178
|
+
class A
|
|
179
|
+
class B
|
|
180
|
+
class Extra
|
|
181
|
+
Root --> A
|
|
182
|
+
A <|-- B
|
|
183
|
+
B --> A`
|
|
184
|
+
const ascii = renderMermaidASCII(src, { useAscii: true })
|
|
185
|
+
expectNoBoxOverlap(ascii, ['Root', 'A', 'B', 'Extra'])
|
|
186
|
+
})
|
|
187
|
+
})
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ============================================================================
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect } from 'vitest'
|
|
6
|
-
import { renderMermaidASCII } from '
|
|
6
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
7
7
|
|
|
8
8
|
describe('ASCII class diagram box compartments', () => {
|
|
9
9
|
it('omits the attrs compartment for a class with methods but no attributes (regression)', () => {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { describe, it, expect } from 'vitest'
|
|
24
|
-
import { renderMermaidASCII } from '
|
|
24
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
25
25
|
|
|
26
26
|
describe('ASCII class diagram — label collision with an intermediate box', () => {
|
|
27
27
|
it('moves a skip-edge label out of an intermediate class box instead of overwriting it', () => {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
import { describe, it, expect } from 'vitest'
|
|
43
|
-
import { renderMermaidASCII } from '
|
|
43
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
44
44
|
|
|
45
45
|
/** paddingY values below the default (5) that the issue found all reproduce
|
|
46
46
|
* the same corruption — the vertical gap floors at 1 row, so nothing about
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { describe, it, expect } from 'vitest'
|
|
19
|
-
import { renderMermaidASCII } from '
|
|
19
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
20
20
|
|
|
21
21
|
describe('ASCII class diagram — label territory is row-aware (issue #447 follow-up)', () => {
|
|
22
22
|
it('does not truncate two labels whose relationships share a source but target different, differently-positioned classes', () => {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// ============================================================================
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest'
|
|
14
|
-
import { renderMermaidASCII } from '
|
|
14
|
+
import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
|
|
15
15
|
|
|
16
16
|
// Two independent, same-level classes — exercises the horizontal gap.
|
|
17
17
|
const SIDE_BY_SIDE = `classDiagram
|